From df5e4a865c8ec7205fe95502c3ec2a8a5b67eef5 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 2 Mar 2021 15:34:46 -0600 Subject: [PATCH] vkd3d-shader: Move some functions into hlsl_codegen.c. Signed-off-by: Zebediah Figura Signed-off-by: Matteo Bruni Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- Makefile.am | 1 + libs/vkd3d-shader/hlsl.h | 2 + libs/vkd3d-shader/hlsl.y | 153 +------------------------- libs/vkd3d-shader/hlsl_codegen.c | 177 +++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 152 deletions(-) create mode 100644 libs/vkd3d-shader/hlsl_codegen.c diff --git a/Makefile.am b/Makefile.am index 3c219e8a..3b09dc7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -160,6 +160,7 @@ libvkd3d_shader_la_SOURCES = \ libs/vkd3d-shader/checksum.c \ libs/vkd3d-shader/dxbc.c \ libs/vkd3d-shader/hlsl.c \ + libs/vkd3d-shader/hlsl_codegen.c \ libs/vkd3d-shader/spirv.c \ libs/vkd3d-shader/trace.c \ libs/vkd3d-shader/vkd3d_shader.map \ diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 33eefe9f..73ba2bec 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -510,6 +510,8 @@ bool hlsl_add_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *decl, bool local_var void hlsl_dump_function(const struct hlsl_ir_function_decl *func) DECLSPEC_HIDDEN; +int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) DECLSPEC_HIDDEN; + void hlsl_free_instr(struct hlsl_ir_node *node) DECLSPEC_HIDDEN; void hlsl_free_instr_list(struct list *list) DECLSPEC_HIDDEN; void hlsl_free_type(struct hlsl_type *type) DECLSPEC_HIDDEN; diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index d733a9b0..ae151181 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -3015,145 +3015,6 @@ expr: %% -static void dump_function_decl(struct rb_entry *entry, void *context) -{ - struct hlsl_ir_function_decl *func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry); - - if (func->body) - hlsl_dump_function(func); -} - -static void dump_function(struct rb_entry *entry, void *context) -{ - struct hlsl_ir_function *func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry); - rb_for_each_entry(&func->overloads, dump_function_decl, NULL); -} - -/* Allocate a unique, ordered index to each instruction, which will be used for - * computing liveness ranges. */ -static unsigned int index_instructions(struct list *instrs, unsigned int index) -{ - struct hlsl_ir_node *instr; - - LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) - { - instr->index = index++; - - if (instr->type == HLSL_IR_IF) - { - struct hlsl_ir_if *iff = hlsl_ir_if(instr); - index = index_instructions(&iff->then_instrs, index); - index = index_instructions(&iff->else_instrs, index); - } - else if (instr->type == HLSL_IR_LOOP) - { - index = index_instructions(&hlsl_ir_loop(instr)->body, index); - hlsl_ir_loop(instr)->next_index = index; - } - } - - return index; -} - -/* Compute the earliest and latest liveness for each variable. In the case that - * a variable is accessed inside of a loop, we promote its liveness to extend - * to at least the range of the entire loop. Note that we don't need to do this - * for anonymous nodes, since there's currently no way to use a node which was - * calculated in an earlier iteration of the loop. */ -static void compute_liveness_recurse(struct list *instrs, unsigned int loop_first, unsigned int loop_last) -{ - struct hlsl_ir_node *instr; - struct hlsl_ir_var *var; - - LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) - { - switch (instr->type) - { - case HLSL_IR_ASSIGNMENT: - { - struct hlsl_ir_assignment *assignment = hlsl_ir_assignment(instr); - - var = assignment->lhs.var; - if (!var->first_write) - var->first_write = loop_first ? min(instr->index, loop_first) : instr->index; - assignment->rhs.node->last_read = instr->index; - if (assignment->lhs.offset.node) - assignment->lhs.offset.node->last_read = instr->index; - break; - } - case HLSL_IR_EXPR: - { - struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(expr->operands) && expr->operands[i].node; ++i) - expr->operands[i].node->last_read = instr->index; - break; - } - case HLSL_IR_IF: - { - struct hlsl_ir_if *iff = hlsl_ir_if(instr); - - compute_liveness_recurse(&iff->then_instrs, loop_first, loop_last); - compute_liveness_recurse(&iff->else_instrs, loop_first, loop_last); - iff->condition.node->last_read = instr->index; - break; - } - case HLSL_IR_LOAD: - { - struct hlsl_ir_load *load = hlsl_ir_load(instr); - - var = load->src.var; - var->last_read = loop_last ? max(instr->index, loop_last) : instr->index; - if (load->src.offset.node) - load->src.offset.node->last_read = instr->index; - break; - } - case HLSL_IR_LOOP: - { - struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); - - compute_liveness_recurse(&loop->body, loop_first ? loop_first : instr->index, - loop_last ? loop_last : loop->next_index); - break; - } - case HLSL_IR_SWIZZLE: - { - struct hlsl_ir_swizzle *swizzle = hlsl_ir_swizzle(instr); - - swizzle->val.node->last_read = instr->index; - break; - } - case HLSL_IR_CONSTANT: - case HLSL_IR_JUMP: - break; - } - } -} - -static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) -{ - struct hlsl_ir_var *var; - - LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) - { - var->first_write = 1; - } - - LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) - { - if (var->modifiers & HLSL_STORAGE_IN) - var->first_write = 1; - if (var->modifiers & HLSL_STORAGE_OUT) - var->last_read = UINT_MAX; - } - - if (entry_func->return_var) - entry_func->return_var->last_read = UINT_MAX; - - compute_liveness_recurse(entry_func->body, 0, 0); -} - int hlsl_parser_compile(struct hlsl_ctx *ctx, const char *entrypoint) { struct hlsl_ir_function_decl *entry_func; @@ -3178,17 +3039,5 @@ int hlsl_parser_compile(struct hlsl_ctx *ctx, const char *entrypoint) "Entry point \"%s\" is missing a return value semantic.", entry_func->func->name); } - list_move_head(entry_func->body, &ctx->static_initializers); - - /* Index 0 means unused; index 1 means function entry, so start at 2. */ - index_instructions(entry_func->body, 2); - - if (TRACE_ON()) - rb_for_each_entry(&ctx->functions, dump_function, NULL); - - compute_liveness(ctx, entry_func); - - if (ctx->failed) - return VKD3D_ERROR_INVALID_SHADER; - return VKD3D_ERROR_NOT_IMPLEMENTED; + return hlsl_emit_dxbc(ctx, entry_func); } diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c new file mode 100644 index 00000000..39984702 --- /dev/null +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -0,0 +1,177 @@ +/* + * HLSL optimization and code generation + * + * Copyright 2019-2020 Zebediah Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "hlsl.h" + +/* Allocate a unique, ordered index to each instruction, which will be used for + * computing liveness ranges. */ +static unsigned int index_instructions(struct list *instrs, unsigned int index) +{ + struct hlsl_ir_node *instr; + + LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) + { + instr->index = index++; + + if (instr->type == HLSL_IR_IF) + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + index = index_instructions(&iff->then_instrs, index); + index = index_instructions(&iff->else_instrs, index); + } + else if (instr->type == HLSL_IR_LOOP) + { + index = index_instructions(&hlsl_ir_loop(instr)->body, index); + hlsl_ir_loop(instr)->next_index = index; + } + } + + return index; +} + +static void dump_function_decl(struct rb_entry *entry, void *context) +{ + struct hlsl_ir_function_decl *func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry); + + if (func->body) + hlsl_dump_function(func); +} + +static void dump_function(struct rb_entry *entry, void *context) +{ + struct hlsl_ir_function *func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry); + rb_for_each_entry(&func->overloads, dump_function_decl, NULL); +} + +/* Compute the earliest and latest liveness for each variable. In the case that + * a variable is accessed inside of a loop, we promote its liveness to extend + * to at least the range of the entire loop. Note that we don't need to do this + * for anonymous nodes, since there's currently no way to use a node which was + * calculated in an earlier iteration of the loop. */ +static void compute_liveness_recurse(struct list *instrs, unsigned int loop_first, unsigned int loop_last) +{ + struct hlsl_ir_node *instr; + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry) + { + switch (instr->type) + { + case HLSL_IR_ASSIGNMENT: + { + struct hlsl_ir_assignment *assignment = hlsl_ir_assignment(instr); + + var = assignment->lhs.var; + if (!var->first_write) + var->first_write = loop_first ? min(instr->index, loop_first) : instr->index; + assignment->rhs.node->last_read = instr->index; + if (assignment->lhs.offset.node) + assignment->lhs.offset.node->last_read = instr->index; + break; + } + case HLSL_IR_EXPR: + { + struct hlsl_ir_expr *expr = hlsl_ir_expr(instr); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(expr->operands) && expr->operands[i].node; ++i) + expr->operands[i].node->last_read = instr->index; + break; + } + case HLSL_IR_IF: + { + struct hlsl_ir_if *iff = hlsl_ir_if(instr); + + compute_liveness_recurse(&iff->then_instrs, loop_first, loop_last); + compute_liveness_recurse(&iff->else_instrs, loop_first, loop_last); + iff->condition.node->last_read = instr->index; + break; + } + case HLSL_IR_LOAD: + { + struct hlsl_ir_load *load = hlsl_ir_load(instr); + + var = load->src.var; + var->last_read = loop_last ? max(instr->index, loop_last) : instr->index; + if (load->src.offset.node) + load->src.offset.node->last_read = instr->index; + break; + } + case HLSL_IR_LOOP: + { + struct hlsl_ir_loop *loop = hlsl_ir_loop(instr); + + compute_liveness_recurse(&loop->body, loop_first ? loop_first : instr->index, + loop_last ? loop_last : loop->next_index); + break; + } + case HLSL_IR_SWIZZLE: + { + struct hlsl_ir_swizzle *swizzle = hlsl_ir_swizzle(instr); + + swizzle->val.node->last_read = instr->index; + break; + } + case HLSL_IR_CONSTANT: + case HLSL_IR_JUMP: + break; + } + } +} + +static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) +{ + struct hlsl_ir_var *var; + + LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) + { + var->first_write = 1; + } + + LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry) + { + if (var->modifiers & HLSL_STORAGE_IN) + var->first_write = 1; + if (var->modifiers & HLSL_STORAGE_OUT) + var->last_read = UINT_MAX; + } + + if (entry_func->return_var) + entry_func->return_var->last_read = UINT_MAX; + + compute_liveness_recurse(entry_func->body, 0, 0); +} + +int hlsl_emit_dxbc(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func) +{ + list_move_head(entry_func->body, &ctx->static_initializers); + + /* Index 0 means unused; index 1 means function entry, so start at 2. */ + index_instructions(entry_func->body, 2); + + if (TRACE_ON()) + rb_for_each_entry(&ctx->functions, dump_function, NULL); + + compute_liveness(ctx, entry_func); + + if (ctx->failed) + return VKD3D_ERROR_INVALID_SHADER; + return VKD3D_ERROR_NOT_IMPLEMENTED; +}