From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- libs/vkd3d-shader/hlsl.y | 6 ++- libs/vkd3d-shader/hlsl_codegen.c | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index d9cbe72f..3d7faabf 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -507,8 +507,12 @@ static struct list *create_loop(struct hlsl_ctx *ctx, enum loop_type type, const
if (iter) { + struct hlsl_block block; + list_move_tail(&iter_block.instrs, iter); - hlsl_block_add_block(&body_block, &iter_block); + if (!hlsl_clone_block(ctx, &block, &iter_block)) + goto oom; + hlsl_block_add_block(&body_block, &block); }
if (type == LOOP_DO_WHILE) diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 6f2ff006..45c12eda 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -4004,6 +4004,74 @@ static void validate_flow_control_usage(struct hlsl_ctx *ctx, const struct hlsl_ } }
+static bool prepend_continue_loop_iterator(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_loop *loop = context; + struct hlsl_ir_jump *jump; + struct hlsl_block iter; + + if (list_empty(&loop->iter.instrs)) + return false; + 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 bool hlsl_transform_loop(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), + struct hlsl_block *block, void *context) +{ + struct hlsl_ir_node *instr, *next; + bool progress = false; + + 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); + + progress |= hlsl_transform_loop(ctx, func, &iff->then_block, context); + progress |= hlsl_transform_loop(ctx, func, &iff->else_block, context); + } + + progress |= func(ctx, instr, context); + } + + return progress; +} + +static void foreach_loop(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), + struct hlsl_block *body) +{ + struct hlsl_ir_node *instr, *next; + + LIST_FOR_EACH_ENTRY_SAFE(instr, next, &body->instrs, struct hlsl_ir_node, entry) + { + if (instr->type == HLSL_IR_IF) + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + + foreach_loop(ctx, func, &iff->then_block); + foreach_loop(ctx, func, &iff->else_block); + } + else if (instr->type == HLSL_IR_LOOP) + { + struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); + + hlsl_transform_loop(ctx, func, &loop->body, loop); + + foreach_loop(ctx, func, &loop->body); + } + } +} + int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out) { @@ -4030,6 +4098,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry while (hlsl_transform_ir(ctx, lower_calls, body, NULL)); /* Check that 'break'/'continue' are used in appropriate context. */ validate_flow_control_usage(ctx, body); + foreach_loop(ctx, prepend_continue_loop_iterator, body);
hlsl_transform_ir(ctx, lower_index_loads, body, NULL);