diff --git a/dlls/d3dcompiler_43/d3dcompiler_private.h b/dlls/d3dcompiler_43/d3dcompiler_private.h index 695ee7d06ef..d7fcfea0d09 100644 --- a/dlls/d3dcompiler_43/d3dcompiler_private.h +++ b/dlls/d3dcompiler_43/d3dcompiler_private.h @@ -694,6 +694,7 @@ enum hlsl_ir_node_type { HLSL_IR_VAR = 0, HLSL_IR_CONSTANT, + HLSL_IR_CONSTRUCTOR, HLSL_IR_DEREF, HLSL_IR_FUNCTION_DECL, }; @@ -788,6 +789,12 @@ struct hlsl_ir_constant } v; }; +struct hlsl_ir_constructor +{ + struct hlsl_ir_node node; + struct list *arguments; +}; + struct hlsl_scope { struct list entry; @@ -847,6 +854,12 @@ static inline struct hlsl_ir_constant *constant_from_node(const struct hlsl_ir_n return CONTAINING_RECORD(node, struct hlsl_ir_constant, node); } +static inline struct hlsl_ir_constructor *constructor_from_node(const struct hlsl_ir_node *node) +{ + assert(node->type == HLSL_IR_CONSTRUCTOR); + return CONTAINING_RECORD(node, struct hlsl_ir_constructor, node); +} + BOOL add_declaration(struct hlsl_scope *scope, struct hlsl_ir_var *decl, BOOL local_var) DECLSPEC_HIDDEN; struct hlsl_ir_var *get_variable(struct hlsl_scope *scope, const char *name) DECLSPEC_HIDDEN; void free_declaration(struct hlsl_ir_var *decl) DECLSPEC_HIDDEN; diff --git a/dlls/d3dcompiler_43/hlsl.y b/dlls/d3dcompiler_43/hlsl.y index 51510025495..a3e5f6e4728 100644 --- a/dlls/d3dcompiler_43/hlsl.y +++ b/dlls/d3dcompiler_43/hlsl.y @@ -112,6 +112,18 @@ static DWORD add_modifier(DWORD modifiers, DWORD mod) return modifiers | mod; } +static unsigned int components_count_expr_list(struct list *list) +{ + struct hlsl_ir_node *node; + unsigned int count = 0; + + LIST_FOR_EACH_ENTRY(node, list, struct hlsl_ir_node, entry) + { + count += components_count_type(node->data_type); + } + return count; +} + %} %error-verbose @@ -793,6 +805,42 @@ postfix_expr: primary_expr { $$ = $1; } + /* "var_modifiers" doesn't make sense in this case, but it's needed + in the grammar to avoid shift/reduce conflicts. */ + | var_modifiers type '(' initializer_expr_list ')' + { + struct hlsl_ir_constructor *constructor; + + TRACE("%s constructor.\n", debug_hlsl_type($2)); + if ($1) + { + hlsl_message("Line %u: unexpected modifier in a constructor.\n", + hlsl_ctx.line_no); + set_parse_status(&hlsl_ctx.status, PARSE_ERR); + return -1; + } + if ($2->type > HLSL_CLASS_LAST_NUMERIC) + { + hlsl_message("Line %u: constructors are allowed only for numeric data types.\n", + hlsl_ctx.line_no); + set_parse_status(&hlsl_ctx.status, PARSE_ERR); + return -1; + } + if ($2->dimx * $2->dimy != components_count_expr_list($4)) + { + hlsl_message("Line %u: wrong number of components in constructor.\n", + hlsl_ctx.line_no); + set_parse_status(&hlsl_ctx.status, PARSE_ERR); + return -1; + } + + constructor = d3dcompiler_alloc(sizeof(*constructor)); + constructor->node.type = HLSL_IR_CONSTRUCTOR; + constructor->node.data_type = $2; + constructor->arguments = $4; + + $$ = &constructor->node; + } unary_expr: postfix_expr { diff --git a/dlls/d3dcompiler_43/utils.c b/dlls/d3dcompiler_43/utils.c index d92243d612b..9c222cd0877 100644 --- a/dlls/d3dcompiler_43/utils.c +++ b/dlls/d3dcompiler_43/utils.c @@ -876,6 +876,32 @@ BOOL find_function(const char *name) return FALSE; } +unsigned int components_count_type(struct hlsl_type *type) +{ + unsigned int count = 0; + struct hlsl_struct_field *field; + + if (type->type <= HLSL_CLASS_LAST_NUMERIC) + { + return type->dimx * type->dimy; + } + if (type->type == HLSL_CLASS_ARRAY) + { + return components_count_type(type->e.array.type) * type->e.array.elements_count; + } + if (type->type != HLSL_CLASS_STRUCT) + { + ERR("Unexpected data type %s.\n", debug_hlsl_type(type)); + return 0; + } + + LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + { + count += components_count_type(field->type); + } + return count; +} + struct hlsl_ir_deref *new_var_deref(struct hlsl_ir_var *var) { struct hlsl_ir_deref *deref = d3dcompiler_alloc(sizeof(*deref)); @@ -1027,6 +1053,7 @@ static const char *debug_node_type(enum hlsl_ir_node_type type) { "HLSL_IR_VAR", "HLSL_IR_CONSTANT", + "HLSL_IR_CONSTRUCTOR", "HLSL_IR_DEREF", "HLSL_IR_FUNCTION_DECL", }; @@ -1112,7 +1139,20 @@ static void debug_dump_ir_constant(const struct hlsl_ir_constant *constant) TRACE("}"); } -static void debug_dump_instr(const struct hlsl_ir_node *instr) +void debug_dump_ir_constructor(const struct hlsl_ir_constructor *constructor) +{ + struct hlsl_ir_node *arg; + + TRACE("%s (", debug_hlsl_type(constructor->node.data_type)); + LIST_FOR_EACH_ENTRY(arg, constructor->arguments, struct hlsl_ir_node, entry) + { + debug_dump_instr(arg); + TRACE(" "); + } + TRACE(")"); +} + +void debug_dump_instr(const struct hlsl_ir_node *instr) { switch (instr->type) { @@ -1122,6 +1162,9 @@ static void debug_dump_instr(const struct hlsl_ir_node *instr) case HLSL_IR_CONSTANT: debug_dump_ir_constant(constant_from_node(instr)); break; + case HLSL_IR_CONSTRUCTOR: + debug_dump_ir_constructor(constructor_from_node(instr)); + break; default: TRACE("No dump function for %s\n", debug_node_type(instr->type)); } @@ -1226,6 +1269,12 @@ static void free_ir_deref(struct hlsl_ir_deref *deref) d3dcompiler_free(deref); } +static void free_ir_constructor(struct hlsl_ir_constructor *constructor) +{ + free_instr_list(constructor->arguments); + d3dcompiler_free(constructor); +} + void free_instr(struct hlsl_ir_node *node) { switch (node->type) @@ -1239,6 +1288,9 @@ void free_instr(struct hlsl_ir_node *node) case HLSL_IR_DEREF: free_ir_deref(deref_from_node(node)); break; + case HLSL_IR_CONSTRUCTOR: + free_ir_constructor(constructor_from_node(node)); + break; default: FIXME("Unsupported node type %s\n", debug_node_type(node->type)); }