-- v5: vkd3d-shader/hlsl: Partially implement static expressions evaluation.
From: Nikolay Sivov nsivov@codeweavers.com
--- Makefile.am | 1 + libs/vkd3d-shader/hlsl.h | 2 + libs/vkd3d-shader/hlsl.y | 86 ++++++++++++-------------- libs/vkd3d-shader/hlsl_codegen.c | 68 ++++++++++---------- tests/hlsl-array-size-expr.shader_test | 40 ++++++++++++ tests/hlsl-invalid.shader_test | 2 +- 6 files changed, 118 insertions(+), 81 deletions(-) create mode 100644 tests/hlsl-array-size-expr.shader_test
diff --git a/Makefile.am b/Makefile.am index e3d52ac5..23519184 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,6 +73,7 @@ vkd3d_shader_tests = \ tests/frac.shader_test \ tests/function-return.shader_test \ tests/hlsl-array-dimension.shader_test \ + tests/hlsl-array-size-expr.shader_test \ tests/hlsl-attributes.shader_test \ tests/hlsl-bool-cast.shader_test \ tests/hlsl-clamp.shader_test \ diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 0256339c..9b5986a5 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -1177,6 +1177,8 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere
bool hlsl_fold_constant_exprs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); bool hlsl_fold_constant_swizzles(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context); +bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), + struct hlsl_block *block, void *context);
bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic, bool output, D3DSHADER_PARAM_REGISTER_TYPE *type, unsigned int *reg); diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index ab0b3f65..d150c1d2 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -1141,54 +1141,32 @@ static struct list *make_list(struct hlsl_ctx *ctx, struct hlsl_ir_node *node) return list; }
-static unsigned int evaluate_static_expression(struct hlsl_ir_node *node) +static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct vkd3d_shader_location *loc) { - if (node->data_type->class != HLSL_CLASS_SCALAR) - return 0; + struct hlsl_ir_constant *constant; + struct hlsl_ir_node *node; + unsigned int ret = 0;
- switch (node->type) - { - case HLSL_IR_CONSTANT: - { - struct hlsl_ir_constant *constant = hlsl_ir_constant(node); - const union hlsl_constant_value_component *value = &constant->value.u[0]; - - switch (constant->node.data_type->base_type) - { - case HLSL_TYPE_UINT: - return value->u; - case HLSL_TYPE_INT: - return value->i; - case HLSL_TYPE_FLOAT: - case HLSL_TYPE_HALF: - return value->f; - case HLSL_TYPE_DOUBLE: - return value->d; - case HLSL_TYPE_BOOL: - return !!value->u; - default: - vkd3d_unreachable(); - } - } + if (!add_implicit_conversion(ctx, &block->instrs, node_from_list(&block->instrs), + hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) + return 0;
- case HLSL_IR_EXPR: - case HLSL_IR_INDEX: - case HLSL_IR_LOAD: - case HLSL_IR_RESOURCE_LOAD: - case HLSL_IR_SWIZZLE: - FIXME("Unhandled type %s.\n", hlsl_node_type_to_string(node->type)); - return 0; + while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, block, NULL));
- case HLSL_IR_CALL: - case HLSL_IR_IF: - case HLSL_IR_JUMP: - case HLSL_IR_LOOP: - case HLSL_IR_RESOURCE_STORE: - case HLSL_IR_STORE: - vkd3d_unreachable(); + node = node_from_list(&block->instrs); + if (node->type == HLSL_IR_CONSTANT) + { + constant = hlsl_ir_constant(node); + ret = constant->value[0].u; + } + else + { + hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, + "Failed to evaluate constant expression %d.", node->type); }
- vkd3d_unreachable(); + return ret; }
static bool expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2) @@ -5076,8 +5054,17 @@ type_no_void: } | texture_ms_type '<' type ',' shift_expr '>' { - unsigned int sample_count = evaluate_static_expression(node_from_list($5)); - destroy_instr_list($5); + unsigned int sample_count; + struct hlsl_block block; + + hlsl_block_init(&block); + list_move_tail(&block.instrs, $5); + + sample_count = evaluate_static_expression_as_uint(ctx, &block, &@5); + + hlsl_block_cleanup(&block); + + vkd3d_free($5);
$$ = hlsl_new_texture_type(ctx, $1, $3, sample_count); } @@ -5270,10 +5257,17 @@ arrays: } | '[' expr ']' arrays { - unsigned int size = evaluate_static_expression(node_from_list($2)); + struct hlsl_block block; uint32_t *new_array; + unsigned int size;
- destroy_instr_list($2); + hlsl_block_init(&block); + list_move_tail(&block.instrs, $2); + + size = evaluate_static_expression_as_uint(ctx, &block, &@2); + + hlsl_block_cleanup(&block); + vkd3d_free($2);
$$ = $4;
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 78c94341..c103841d 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -573,7 +573,7 @@ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st append_output_copy_recurse(ctx, instrs, load, var->storage_modifiers, &var->semantic, var->semantic.index); }
-static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), +bool hlsl_transform_ir(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; @@ -585,11 +585,11 @@ static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx { struct hlsl_ir_if *iff = hlsl_ir_if(instr);
- progress |= transform_ir(ctx, func, &iff->then_block, context); - progress |= transform_ir(ctx, func, &iff->else_block, context); + progress |= hlsl_transform_ir(ctx, func, &iff->then_block, context); + progress |= hlsl_transform_ir(ctx, func, &iff->else_block, context); } else if (instr->type == HLSL_IR_LOOP) - progress |= transform_ir(ctx, func, &hlsl_ir_loop(instr)->body, context); + progress |= hlsl_transform_ir(ctx, func, &hlsl_ir_loop(instr)->body, context);
progress |= func(ctx, instr, context); } @@ -632,7 +632,7 @@ static bool find_recursive_calls(struct hlsl_ctx *ctx, struct hlsl_ir_node *inst return false; call_ctx->backtrace[call_ctx->count++] = decl;
- transform_ir(ctx, find_recursive_calls, &decl->body, call_ctx); + hlsl_transform_ir(ctx, find_recursive_calls, &decl->body, call_ctx);
--call_ctx->count;
@@ -694,7 +694,7 @@ static bool lower_return(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fun * the CF instruction, shove it into an if block, and then lower that if * block. * - * (We could return a "did we make progress" boolean like transform_ir() + * (We could return a "did we make progress" boolean like hlsl_transform_ir() * and run this pass multiple times, but we already know the only block * that still needs to be addressed, so there's not much point.) * @@ -3561,7 +3561,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry list_move_head(&body->instrs, &ctx->static_initializers);
memset(&recursive_call_ctx, 0, sizeof(recursive_call_ctx)); - transform_ir(ctx, find_recursive_calls, body, &recursive_call_ctx); + hlsl_transform_ir(ctx, find_recursive_calls, body, &recursive_call_ctx); vkd3d_free(recursive_call_ctx.backtrace);
/* Avoid going into an infinite loop when processing call instructions. @@ -3571,9 +3571,9 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
lower_return(ctx, entry_func, body, false);
- while (transform_ir(ctx, lower_calls, body, NULL)); + while (hlsl_transform_ir(ctx, lower_calls, body, NULL));
- transform_ir(ctx, lower_index_loads, body, NULL); + hlsl_transform_ir(ctx, lower_index_loads, body, NULL);
LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) { @@ -3629,54 +3629,54 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_ATTRIBUTE, "Entry point "%s" is missing a [numthreads] attribute.", entry_func->func->name);
- transform_ir(ctx, lower_broadcasts, body, NULL); - while (transform_ir(ctx, fold_redundant_casts, body, NULL)); + hlsl_transform_ir(ctx, lower_broadcasts, body, NULL); + while (hlsl_transform_ir(ctx, fold_redundant_casts, body, NULL)); do { - progress = transform_ir(ctx, split_array_copies, body, NULL); - progress |= transform_ir(ctx, split_struct_copies, body, NULL); + progress = hlsl_transform_ir(ctx, split_array_copies, body, NULL); + progress |= hlsl_transform_ir(ctx, split_struct_copies, body, NULL); } while (progress); - transform_ir(ctx, split_matrix_copies, body, NULL); - - transform_ir(ctx, lower_narrowing_casts, body, NULL); - transform_ir(ctx, lower_casts_to_bool, body, NULL); - transform_ir(ctx, lower_int_division, body, NULL); - transform_ir(ctx, lower_int_modulus, body, NULL); - transform_ir(ctx, lower_int_abs, body, NULL); - transform_ir(ctx, lower_float_modulus, body, NULL); + hlsl_transform_ir(ctx, split_matrix_copies, body, NULL); + + hlsl_transform_ir(ctx, lower_narrowing_casts, body, NULL); + hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL); + hlsl_transform_ir(ctx, lower_int_division, body, NULL); + hlsl_transform_ir(ctx, lower_int_modulus, body, NULL); + hlsl_transform_ir(ctx, lower_int_abs, body, NULL); + hlsl_transform_ir(ctx, lower_float_modulus, body, NULL); do { - progress = transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL); - progress |= transform_ir(ctx, hlsl_fold_constant_swizzles, body, NULL); + progress = hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL); + progress |= hlsl_transform_ir(ctx, hlsl_fold_constant_swizzles, body, NULL); progress |= copy_propagation_execute(ctx, body); - progress |= transform_ir(ctx, fold_swizzle_chains, body, NULL); - progress |= transform_ir(ctx, remove_trivial_swizzles, body, NULL); + progress |= hlsl_transform_ir(ctx, fold_swizzle_chains, body, NULL); + progress |= hlsl_transform_ir(ctx, remove_trivial_swizzles, body, NULL); } while (progress);
if (profile->major_version < 4) { - transform_ir(ctx, lower_division, body, NULL); - transform_ir(ctx, lower_sqrt, body, NULL); - transform_ir(ctx, lower_dot, body, NULL); - transform_ir(ctx, lower_round, body, NULL); + hlsl_transform_ir(ctx, lower_division, body, NULL); + hlsl_transform_ir(ctx, lower_sqrt, body, NULL); + hlsl_transform_ir(ctx, lower_dot, body, NULL); + hlsl_transform_ir(ctx, lower_round, body, NULL); }
if (profile->major_version < 2) { - transform_ir(ctx, lower_abs, body, NULL); + hlsl_transform_ir(ctx, lower_abs, body, NULL); }
- transform_ir(ctx, validate_static_object_references, body, NULL); + hlsl_transform_ir(ctx, validate_static_object_references, body, NULL);
/* TODO: move forward, remove when no longer needed */ - transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL); - while (transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL)); + hlsl_transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL); + while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL));
do compute_liveness(ctx, entry_func); - while (transform_ir(ctx, dce, body, NULL)); + while (hlsl_transform_ir(ctx, dce, body, NULL));
compute_liveness(ctx, entry_func);
diff --git a/tests/hlsl-array-size-expr.shader_test b/tests/hlsl-array-size-expr.shader_test new file mode 100644 index 00000000..0d64462b --- /dev/null +++ b/tests/hlsl-array-size-expr.shader_test @@ -0,0 +1,40 @@ +[pixel shader] +static const float4 array_st[(2 + 1) * 2] = { + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44, + 51, 52, 53, 54, + 61, 62, 63, 64, +}; + +float4 main() : SV_TARGET +{ + return array_st[1]; +} + +[test] +draw quad +probe all rgba (21, 22, 23, 24) + + +[pixel shader] +static const float4 array_st[2*2][1+1] = { + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44, + 51, 52, 53, 54, + 61, 62, 63, 64, + 71, 72, 73, 74, + 81, 82, 83, 84, +}; + +float4 main() : SV_TARGET +{ + return array_st[2][1]; +} + +[test] +draw quad +probe all rgba (61, 62, 63, 64) diff --git a/tests/hlsl-invalid.shader_test b/tests/hlsl-invalid.shader_test index ad062652..61033811 100644 --- a/tests/hlsl-invalid.shader_test +++ b/tests/hlsl-invalid.shader_test @@ -72,7 +72,7 @@ float4 main() : sv_target return 0; }
-[pixel shader fail] +[pixel shader fail todo] float4 main() : sv_target { int x;