vkd3d-shader/hlsl: Handle 'continue' statements.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
Nikolay Sivov 2023-09-25 20:29:54 +02:00 committed by Alexandre Julliard
parent 0e5749e78e
commit e4b423d6b5
Notes: Alexandre Julliard 2023-10-09 23:10:18 +02:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Zebediah Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/245
3 changed files with 72 additions and 0 deletions

View File

@ -2558,6 +2558,10 @@ static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_i
case HLSL_IR_JUMP_RETURN:
vkd3d_string_buffer_printf(buffer, "return");
break;
case HLSL_IR_JUMP_UNRESOLVED_CONTINUE:
vkd3d_string_buffer_printf(buffer, "unresolved_continue");
break;
}
}

View File

@ -574,6 +574,10 @@ enum hlsl_ir_jump_type
HLSL_IR_JUMP_DISCARD_NEG,
HLSL_IR_JUMP_DISCARD_NZ,
HLSL_IR_JUMP_RETURN,
/* UNRESOLVED_CONTINUE type is used by the parser when 'continue' statement is found,
it never reaches code generation, and is resolved to CONTINUE type once iteration
and loop exit logic was properly applied. */
HLSL_IR_JUMP_UNRESOLVED_CONTINUE,
};
struct hlsl_ir_jump

View File

@ -464,6 +464,50 @@ static bool attribute_list_has_duplicates(const struct parse_attribute_list *att
return false;
}
static void resolve_loop_continue(struct hlsl_ctx *ctx, struct hlsl_block *block, enum loop_type type,
struct hlsl_block *cond, struct hlsl_block *iter)
{
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);
resolve_loop_continue(ctx, &iff->then_block, type, cond, iter);
resolve_loop_continue(ctx, &iff->else_block, type, cond, iter);
}
else if (instr->type == HLSL_IR_JUMP)
{
struct hlsl_ir_jump *jump = hlsl_ir_jump(instr);
struct hlsl_block block;
if (jump->type != HLSL_IR_JUMP_UNRESOLVED_CONTINUE)
continue;
if (type == LOOP_DO_WHILE)
{
if (!hlsl_clone_block(ctx, &block, cond))
return;
if (!append_conditional_break(ctx, &block))
{
hlsl_block_cleanup(&block);
return;
}
list_move_before(&instr->entry, &block.instrs);
}
else if (type == LOOP_FOR)
{
if (!hlsl_clone_block(ctx, &block, iter))
return;
list_move_before(&instr->entry, &block.instrs);
}
jump->type = HLSL_IR_JUMP_CONTINUE;
}
}
}
static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type,
const struct parse_attribute_list *attributes, struct hlsl_block *init, struct hlsl_block *cond,
struct hlsl_block *iter, struct hlsl_block *body, const struct vkd3d_shader_location *loc)
@ -501,6 +545,8 @@ static struct hlsl_block *create_loop(struct hlsl_ctx *ctx, enum loop_type type,
}
}
resolve_loop_continue(ctx, body, type, cond, iter);
if (!init && !(init = make_empty_block(ctx)))
goto oom;
@ -6137,6 +6183,24 @@ jump_statement:
YYABORT;
hlsl_block_add_instr($$, jump);
}
| KW_CONTINUE ';'
{
struct hlsl_ir_node *jump;
struct hlsl_scope *scope;
if (!(scope = get_loop_scope(ctx->cur_scope)))
{
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'continue' statement must be used inside of a loop.");
}
if (!($$ = make_empty_block(ctx)))
YYABORT;
if (!(jump = hlsl_new_jump(ctx, HLSL_IR_JUMP_UNRESOLVED_CONTINUE, NULL, &@1)))
YYABORT;
hlsl_block_add_instr($$, jump);
}
| KW_RETURN expr ';'
{
$$ = $2;