From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index fb6d485ea..ab9f81a38 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -6061,7 +6061,19 @@ statement: | loop_statement
jump_statement: - KW_RETURN expr ';' + KW_BREAK ';' + { + struct hlsl_ir_node *jump; + + /* TODO: check that it's used in appropriate context. */ + + if (!($$ = make_empty_block(ctx))) + YYABORT; + if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_BREAK, NULL, &@1))) + YYABORT; + hlsl_block_add_instr($$, jump); + } + | KW_RETURN expr ';' { $$ = $2; if (!add_return(ctx, $$, node_from_block($$), &@1))
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- Makefile.am | 1 + libs/vkd3d-shader/hlsl.c | 112 ++++++++++++++++++++++ libs/vkd3d-shader/hlsl.h | 25 +++++ libs/vkd3d-shader/hlsl.l | 4 +- libs/vkd3d-shader/hlsl.y | 50 ++++++++++ libs/vkd3d-shader/hlsl_codegen.c | 128 +++++++++++++++++++++++++- libs/vkd3d-shader/tpf.c | 43 +++++++++ libs/vkd3d-shader/vkd3d_shader_main.c | 3 +- tests/hlsl/switch.shader_test | 29 ++++++ 9 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 tests/hlsl/switch.shader_test
diff --git a/Makefile.am b/Makefile.am index 744e46127..9a0c9034e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -163,6 +163,7 @@ vkd3d_shader_tests = \ tests/hlsl/struct-array.shader_test \ tests/hlsl/struct-assignment.shader_test \ tests/hlsl/struct-semantics.shader_test \ + tests/hlsl/switch.shader_test \ tests/hlsl/swizzle-constant-prop.shader_test \ tests/hlsl/swizzle-matrix.shader_test \ tests/hlsl/swizzles.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 5fe9047bf..f2c0c2a6a 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -1325,6 +1325,38 @@ struct hlsl_ir_node *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *cond return &iff->node; }
+struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, struct hlsl_ir_node *value, + struct hlsl_block *block) +{ + struct hlsl_ir_switch_case *c; + + if (!(c = hlsl_alloc(ctx, sizeof(*c)))) + return NULL; + if (value) + hlsl_src_from_node(&c->value, value); + hlsl_block_init(&c->body); + if (block) + hlsl_block_add_block(&c->body, block); + + return c; +} + +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_switch *s; + + if (!(s = hlsl_alloc(ctx, sizeof(*s)))) + return NULL; + init_node(&s->node, HLSL_IR_SWITCH, NULL, loc); + hlsl_src_from_node(&s->selector, selector); + list_init(&s->cases); + if (cases) + list_move_head(&s->cases, cases); + + return &s->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) { @@ -1787,6 +1819,29 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr return dst; }
+static struct hlsl_ir_node *clone_switch(struct hlsl_ctx *ctx, + struct clone_instr_map *map, struct hlsl_ir_switch *s) +{ + struct hlsl_ir_switch_case *c, *d; + struct hlsl_block body; + struct list cases; + + list_init(&cases); + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + clone_block(ctx, &body, &c->body, map); + + if (!(d = hlsl_new_switch_case(ctx, NULL, &body))) + return NULL; + + clone_src(map, &d->value, &c->value); + list_add_tail(&cases, &d->entry); + } + + return hlsl_new_switch(ctx, map_instr(map, s->selector.node), &cases, &s->node.loc); +} + static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, struct clone_instr_map *map, const struct hlsl_ir_node *instr) { @@ -1825,6 +1880,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx, case HLSL_IR_STORE: return clone_store(ctx, map, hlsl_ir_store(instr));
+ case HLSL_IR_SWITCH: + return clone_switch(ctx, map, hlsl_ir_switch(instr)); + case HLSL_IR_SWIZZLE: return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr)); } @@ -2239,6 +2297,7 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type) [HLSL_IR_RESOURCE_LOAD ] = "HLSL_IR_RESOURCE_LOAD", [HLSL_IR_RESOURCE_STORE] = "HLSL_IR_RESOURCE_STORE", [HLSL_IR_STORE ] = "HLSL_IR_STORE", + [HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH", [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", };
@@ -2659,6 +2718,35 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_ vkd3d_string_buffer_printf(buffer, "]"); }
+static void dump_ir_switch(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_switch *s) +{ + struct hlsl_ir_switch_case *c; + + vkd3d_string_buffer_printf(buffer, "switch ("); + dump_src(buffer, &s->selector); + vkd3d_string_buffer_printf(buffer, ") {\n"); + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + if (c->value.node) + { + vkd3d_string_buffer_printf(buffer, " case "); + dump_src(buffer, &c->value); + vkd3d_string_buffer_printf(buffer, ": {\n"); + } + else + { + vkd3d_string_buffer_printf(buffer, " default: {\n"); + } + + vkd3d_string_buffer_printf(buffer, " "); + dump_block(ctx, buffer, &c->body); + vkd3d_string_buffer_printf(buffer, " };\n"); + } + + vkd3d_string_buffer_printf(buffer, "}\n"); +} + static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_node *instr) { if (instr->index) @@ -2714,6 +2802,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, dump_ir_store(buffer, hlsl_ir_store(instr)); break;
+ case HLSL_IR_SWITCH: + dump_ir_switch(ctx, buffer, hlsl_ir_switch(instr)); + break; + case HLSL_IR_SWIZZLE: dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); break; @@ -2874,6 +2966,22 @@ static void free_ir_swizzle(struct hlsl_ir_swizzle *swizzle) vkd3d_free(swizzle); }
+static void free_ir_switch(struct hlsl_ir_switch *s) +{ + struct hlsl_ir_switch_case *c, *next_c; + + hlsl_src_remove(&s->selector); + + LIST_FOR_EACH_ENTRY_SAFE(c, next_c, &s->cases, struct hlsl_ir_switch_case, entry) + { + hlsl_src_remove(&c->value); + hlsl_block_cleanup(&c->body); + list_remove(&c->entry); + vkd3d_free(c); + } + vkd3d_free(s); +} + static void free_ir_index(struct hlsl_ir_index *index) { hlsl_src_remove(&index->val); @@ -2934,6 +3042,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node) case HLSL_IR_SWIZZLE: free_ir_swizzle(hlsl_ir_swizzle(node)); break; + + case HLSL_IR_SWITCH: + free_ir_switch(hlsl_ir_switch(node)); + break; } }
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 44cebaaf6..f7ea0e4d3 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -284,6 +284,7 @@ enum hlsl_ir_node_type HLSL_IR_RESOURCE_STORE, HLSL_IR_STORE, HLSL_IR_SWIZZLE, + HLSL_IR_SWITCH, };
/* Common data for every type of IR instruction node. */ @@ -497,6 +498,20 @@ struct hlsl_ir_loop unsigned int next_index; /* liveness index of the end of the loop */ };
+struct hlsl_ir_switch_case +{ + struct hlsl_src value; + struct hlsl_block body; + struct list entry; +}; + +struct hlsl_ir_switch +{ + struct hlsl_ir_node node; + struct hlsl_src selector; + struct list cases; +}; + enum hlsl_ir_expr_op { HLSL_OP0_VOID, @@ -944,6 +959,12 @@ static inline struct hlsl_ir_index *hlsl_ir_index(const struct hlsl_ir_node *nod return CONTAINING_RECORD(node, struct hlsl_ir_index, node); }
+static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *node) +{ + assert(node->type == HLSL_IR_SWITCH); + return CONTAINING_RECORD(node, struct hlsl_ir_switch, node); +} + static inline void hlsl_block_init(struct hlsl_block *block) { list_init(&block->instrs); @@ -1210,6 +1231,10 @@ struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type, const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, unsigned int modifiers, const struct hlsl_reg_reservation *reg_reservation); +struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, struct hlsl_ir_node *value, + struct hlsl_block *block); +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);
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); diff --git a/libs/vkd3d-shader/hlsl.l b/libs/vkd3d-shader/hlsl.l index e9ae3ccf3..09815995d 100644 --- a/libs/vkd3d-shader/hlsl.l +++ b/libs/vkd3d-shader/hlsl.l @@ -46,7 +46,7 @@ static void update_location(struct hlsl_ctx *ctx, YYLTYPE *loc);
%x pp pp_line pp_pragma pp_ignore
-RESERVED1 auto|case|catch|char|class|const_cast|default|delete|dynamic_cast|enum +RESERVED1 auto|catch|char|class|const_cast|delete|dynamic_cast|enum RESERVED2 explicit|friend|goto|long|mutable|new|operator|private|protected|public RESERVED3 reinterpret_cast|short|signed|sizeof|static_cast|template|this|throw|try RESERVED4 typename|union|unsigned|using|virtual @@ -73,12 +73,14 @@ ANY (.) BlendState {return KW_BLENDSTATE; } break {return KW_BREAK; } Buffer {return KW_BUFFER; } +case {return KW_CASE; } cbuffer {return KW_CBUFFER; } compile {return KW_COMPILE; } const {return KW_CONST; } continue {return KW_CONTINUE; } DepthStencilState {return KW_DEPTHSTENCILSTATE; } DepthStencilView {return KW_DEPTHSTENCILVIEW; } +default {return KW_DEFAULT; } discard {return KW_DISCARD; } do {return KW_DO; } double {return KW_DOUBLE; } diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ab9f81a38..66069c06b 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1134,6 +1134,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str case HLSL_IR_RESOURCE_LOAD: case HLSL_IR_RESOURCE_STORE: case HLSL_IR_STORE: + case HLSL_IR_SWITCH: hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Expected literal expression."); } @@ -4587,11 +4588,13 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %token KW_BLENDSTATE %token KW_BREAK %token KW_BUFFER +%token KW_CASE %token KW_CBUFFER %token KW_COLUMN_MAJOR %token KW_COMPILE %token KW_CONST %token KW_CONTINUE +%token KW_DEFAULT %token KW_DEPTHSTENCILSTATE %token KW_DEPTHSTENCILVIEW %token KW_DISCARD @@ -4695,6 +4698,8 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %type <list> type_specs %type <list> variables_def %type <list> variables_def_typed +%type <list> switch_case +%type <list> switch_cases
%token <name> VAR_IDENTIFIER %token <name> NEW_IDENTIFIER @@ -4737,6 +4742,7 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %type <block> statement %type <block> statement_list %type <block> struct_declaration_without_vars +%type <block> switch_statement %type <block> unary_expr
%type <boolval> boolean @@ -6059,6 +6065,7 @@ statement: | jump_statement | selection_statement | loop_statement + | switch_statement
jump_statement: KW_BREAK ';' @@ -6181,6 +6188,49 @@ loop_statement: hlsl_pop_scope(ctx); }
+switch_statement: + attribute_list_optional KW_SWITCH '(' expr ')' '{' switch_cases '}' + { + struct hlsl_ir_node *selector = node_from_block($4); + struct hlsl_ir_node *s; + + if (!(s = hlsl_new_switch(ctx, selector, $7, &@2))) + YYABORT; + vkd3d_free($7); + $$ = $4; + hlsl_block_add_instr($$, s); + } + +switch_case: + KW_CASE expr ':' statement_list + { + struct hlsl_ir_node *value = node_from_block($2); + hlsl_block_add_block($2, $4); + $$ = &hlsl_new_switch_case(ctx, value, $2)->entry; + } + | KW_CASE expr ':' + { + struct hlsl_ir_node *value = node_from_block($2); + $$ = &hlsl_new_switch_case(ctx, value, NULL)->entry; + } + | KW_DEFAULT ':' statement_list + { + $$ = &hlsl_new_switch_case(ctx, NULL, $3)->entry; + } + +switch_cases: + switch_case + { + if (!($$ = make_empty_list(ctx))) + YYABORT; + list_add_head($$, $1); + } + | switch_cases switch_case + { + $$ = $1; + list_add_tail($$, $2); + } + expr_optional: %empty { diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index be0248421..3a9765e5d 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -562,7 +562,19 @@ bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, progress |= hlsl_transform_ir(ctx, func, &iff->else_block, context); } else if (instr->type == HLSL_IR_LOOP) + { progress |= hlsl_transform_ir(ctx, func, &hlsl_ir_loop(instr)->body, context); + } + else if (instr->type == HLSL_IR_SWITCH) + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + progress |= hlsl_transform_ir(ctx, func, &c->body, context); + } + }
progress |= func(ctx, instr, context); } @@ -822,6 +834,28 @@ static bool lower_return(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fun } } } + else if (instr->type == HLSL_IR_SWITCH) + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + has_early_return |= lower_return(ctx, func, &c->body, true); + } + + if (has_early_return) + { + /* If we're in a loop, we don't need to do anything here. We + * turned the return into a break, and that will already skip + * anything that comes after this "if" block. */ + if (!in_loop) + { + cf_instr = instr; + break; + } + } + } }
if (return_instr) @@ -1632,6 +1666,19 @@ static void copy_propagation_invalidate_from_block(struct hlsl_ctx *ctx, struct break; }
+ case HLSL_IR_SWITCH: + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + copy_propagation_invalidate_from_block(ctx, state, &c->body); + } + + break; + } + default: break; } @@ -1680,6 +1727,28 @@ static bool copy_propagation_process_loop(struct hlsl_ctx *ctx, struct hlsl_ir_l return progress; }
+static bool copy_propagation_process_switch(struct hlsl_ctx *ctx, struct hlsl_ir_switch *s, + struct copy_propagation_state *state) +{ + struct copy_propagation_state inner_state; + struct hlsl_ir_switch_case *c; + bool progress = false; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + copy_propagation_state_init(ctx, &inner_state, state); + progress |= copy_propagation_transform_block(ctx, &c->body, &inner_state); + copy_propagation_state_destroy(&inner_state); + } + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + copy_propagation_invalidate_from_block(ctx, state, &c->body); + } + + return progress; +} + static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_block *block, struct copy_propagation_state *state) { @@ -1718,7 +1787,15 @@ static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_b progress |= copy_propagation_process_loop(ctx, hlsl_ir_loop(instr), state); break;
- default: + case HLSL_IR_SWITCH: + progress |= copy_propagation_process_switch(ctx, hlsl_ir_switch(instr), state); + break; + + case HLSL_IR_CALL: + case HLSL_IR_CONSTANT: + case HLSL_IR_EXPR: + case HLSL_IR_INDEX: + case HLSL_IR_JUMP: break; } } @@ -2922,6 +2999,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) case HLSL_IR_JUMP: case HLSL_IR_LOOP: case HLSL_IR_RESOURCE_STORE: + case HLSL_IR_SWITCH: break; }
@@ -2949,6 +3027,16 @@ static unsigned int index_instructions(struct hlsl_block *block, unsigned int in index = index_instructions(&hlsl_ir_loop(instr)->body, index); hlsl_ir_loop(instr)->next_index = index; } + else if (instr->type == HLSL_IR_SWITCH) + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + index = index_instructions(&c->body, index); + } + } }
return index; @@ -3158,6 +3246,20 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop jump->condition.node->last_read = last_read; break; } + case HLSL_IR_SWITCH: + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + compute_liveness_recurse(&c->body, loop_first, loop_last); + if (c->value.node) + c->value.node->last_read = last_read; + } + s->selector.node->last_read = last_read; + break; + } case HLSL_IR_CONSTANT: break; } @@ -3508,6 +3610,18 @@ static void allocate_temp_registers_recurse(struct hlsl_ctx *ctx, break; }
+ case HLSL_IR_SWITCH: + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + allocate_temp_registers_recurse(ctx, &c->body, allocator); + } + break; + } + default: break; } @@ -3617,6 +3731,18 @@ static void allocate_const_registers_recurse(struct hlsl_ctx *ctx, break; }
+ case HLSL_IR_SWITCH: + { + struct hlsl_ir_switch *s = hlsl_ir_switch(instr); + struct hlsl_ir_switch_case *c; + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + allocate_const_registers_recurse(ctx, &c->body, allocator); + } + break; + } + default: break; } diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 045fb6c5f..9a02ea45b 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -5430,6 +5430,45 @@ static void write_sm4_store(const struct tpf_writer *tpf, const struct hlsl_ir_s write_sm4_instruction(tpf, &instr); }
+static void write_sm4_switch(const struct tpf_writer *tpf, const struct hlsl_ir_switch *s) +{ + const struct hlsl_ir_node *selector = s->selector.node; + struct hlsl_ir_switch_case *c; + struct sm4_instruction instr; + + memset(&instr, 0, sizeof(instr)); + instr.opcode = VKD3D_SM4_OP_SWITCH; + + sm4_src_from_node(&instr.srcs[0], selector, VKD3DSP_WRITEMASK_ALL); + instr.src_count = 1; + + write_sm4_instruction(tpf, &instr); + + LIST_FOR_EACH_ENTRY(c, &s->cases, struct hlsl_ir_switch_case, entry) + { + memset(&instr, 0, sizeof(instr)); + if (c->value.node) + { + instr.opcode = VKD3D_SM4_OP_CASE; + + sm4_src_from_node(&instr.srcs[0], c->value.node, VKD3DSP_WRITEMASK_ALL); + instr.src_count = 1; + } + else + { + instr.opcode = VKD3D_SM4_OP_DEFAULT; + } + + write_sm4_instruction(tpf, &instr); + write_sm4_block(tpf, &c->body); + } + + memset(&instr, 0, sizeof(instr)); + instr.opcode = VKD3D_SM4_OP_ENDSWITCH; + + write_sm4_instruction(tpf, &instr); +} + static void write_sm4_swizzle(const struct tpf_writer *tpf, const struct hlsl_ir_swizzle *swizzle) { struct sm4_instruction instr; @@ -5515,6 +5554,10 @@ static void write_sm4_block(const struct tpf_writer *tpf, const struct hlsl_bloc write_sm4_store(tpf, hlsl_ir_store(instr)); break;
+ case HLSL_IR_SWITCH: + write_sm4_switch(tpf, hlsl_ir_switch(instr)); + break; + case HLSL_IR_SWIZZLE: write_sm4_swizzle(tpf, hlsl_ir_swizzle(instr)); break; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 9ccb917c8..ae0312d45 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -981,8 +981,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte cf_info->type = VKD3D_SHADER_BLOCK_SWITCH; break; case VKD3DSIH_ENDSWITCH: - if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) - || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH || cf_info->inside_block) + if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH) { vkd3d_shader_scan_error(context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘endswitch’ instruction without corresponding ‘switch’ block."); diff --git a/tests/hlsl/switch.shader_test b/tests/hlsl/switch.shader_test new file mode 100644 index 000000000..799ff3fdd --- /dev/null +++ b/tests/hlsl/switch.shader_test @@ -0,0 +1,29 @@ +[require] +shader model >= 4.0 + +[pixel shader] +uint4 v; + +float4 main() : sv_target +{ + switch (v.x) + { + case 0: + return 3.0; + case 1: + return 4.0; + default: + return 5.0; + } +} + +[test] +uniform 0 uint4 3 0 0 0 +draw quad +probe all rgba (5.0, 5.0, 5.0, 5.0) +uniform 0 uint4 1 0 0 0 +draw quad +probe all rgba (4.0, 4.0, 4.0, 4.0) +uniform 0 uint4 0 0 0 0 +draw quad +probe all rgba (3.0, 3.0, 3.0, 3.0)