From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 69 ++++++++++++++++++++++++++++++-- libs/vkd3d-shader/hlsl_codegen.c | 6 ++- 2 files changed, 69 insertions(+), 6 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 6b010493..f65c82c8 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -454,10 +454,48 @@ static bool attribute_list_has_duplicates(const struct parse_attribute_list *att return false; }
-static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const struct parse_attribute_list *attributes, struct list *init, struct list *cond, - struct list *iter, struct list *body, const struct vkd3d_shader_location *loc) +static void transform_loop_body(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), + struct hlsl_block *block, void *context) { - struct hlsl_block body_block; + struct hlsl_ir_node *instr, *next; + + LIST_FOR_EACH_ENTRY_SAFE(instr, next, &block->instrs, struct hlsl_ir_node, entry) + { + if (instr->type == HLSL_IR_IF) + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + + transform_loop_body(ctx, func, &iff->then_block, context); + transform_loop_body(ctx, func, &iff->else_block, context); + } + + func(ctx, instr, context); + } +} + +static bool prepend_continue_loop_iterator(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_block *loop_iter = context; + struct hlsl_ir_jump *jump; + struct hlsl_block iter; + + if (instr->type != HLSL_IR_JUMP) + return false; + jump = hlsl_ir_jump(instr); + if (jump->type != HLSL_IR_JUMP_CONTINUE) + return false; + + if (!hlsl_clone_block(ctx, &iter, loop_iter)) + return false; + list_move_before(&instr->entry, &iter.instrs); + + return true; +} + +static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const struct parse_attribute_list *attributes, + struct list *init, struct list *cond, struct list *iter, struct list *body, const struct vkd3d_shader_location *loc) +{ + struct hlsl_block body_block, iter_block; struct hlsl_ir_node *loop; unsigned int i;
@@ -498,6 +536,7 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const goto oom;
hlsl_block_init(&body_block); + hlsl_block_init(&iter_block);
if (type != LOOP_DO_WHILE) list_move_tail(&body_block.instrs, cond); @@ -505,11 +544,23 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const list_move_tail(&body_block.instrs, body);
if (iter) - list_move_tail(&body_block.instrs, iter); + { + struct hlsl_block block; + + list_move_tail(&iter_block.instrs, iter); + if (!hlsl_clone_block(ctx, &block, &iter_block)) + goto oom; + hlsl_block_add_block(&body_block, &block); + }
if (type == LOOP_DO_WHILE) list_move_tail(&body_block.instrs, cond);
+ if (!list_empty(&iter_block.instrs)) + transform_loop_body(ctx, prepend_continue_loop_iterator, &body_block, &iter_block); + + hlsl_block_cleanup(&iter_block); + if (!(loop = hlsl_new_loop(ctx, &body_block, loc))) goto oom; list_add_tail(init, &loop->entry); @@ -5729,6 +5780,16 @@ jump_statement: YYABORT; list_add_tail($$, &jump->entry); } + | KW_CONTINUE ';' + { + struct hlsl_ir_node *jump; + + if (!($$ = make_empty_list(ctx))) + YYABORT; + if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_CONTINUE, &@1))) + YYABORT; + list_add_tail($$, &jump->entry); + } | KW_RETURN expr ';' { if (!add_return(ctx, $2, node_from_list($2), &@1)) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 5c10ec8b..a7c4d237 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4000,10 +4000,12 @@ static void validate_flow_control_usage(struct hlsl_ctx *ctx, const struct hlsl_ { struct hlsl_ir_jump *jump = hlsl_ir_jump(instr);
- if (jump->type == HLSL_IR_JUMP_BREAK) + if (jump->type == HLSL_IR_JUMP_BREAK + || jump->type == HLSL_IR_JUMP_CONTINUE) { hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, - "Flow control instruction "break" can't be used in this context."); + "Flow control instruction "%s" can't be used in this context.", + jump->type == HLSL_IR_JUMP_BREAK ? "break" : "continue"); } } }