vkd3d-shader/hlsl: Parse the shader 'compile' syntax.

The hlsl_ir_compile node is introduced to represent the "compile"
syntax, and later the CompileShader() and ConstructGSWithSO()
constructs.

It basically represents a function call that remembers its arguments
using hlsl_srcs and keeps its own instruction block, which is discarded
when working on non-effect shaders.

For shader compilations it can be asserted that args_count is 1, and
that this argument (and the last node in hlsl_ir_effect_call.instrs)
is a regular hlsl_ir_call pointing to the declaration of the function
to be compiled.
This commit is contained in:
Francisco Casas
2024-06-24 17:30:46 -04:00
committed by Henri Verbeet
parent 379cd9b7b5
commit 45f18a7838
Notes: Henri Verbeet 2024-09-04 18:48:35 +02:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/943
6 changed files with 339 additions and 46 deletions

View File

@@ -628,6 +628,7 @@ static struct hlsl_default_value evaluate_static_expression(struct hlsl_ctx *ctx
case HLSL_IR_RESOURCE_LOAD:
case HLSL_IR_RESOURCE_STORE:
case HLSL_IR_SWITCH:
case HLSL_IR_COMPILE:
case HLSL_IR_STATEBLOCK_CONSTANT:
hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"Expected literal expression.");
@@ -2735,13 +2736,15 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
if (v->initializer.args_count)
{
unsigned int store_index = 0;
bool is_default_values_initializer;
unsigned int store_index = 0;
unsigned int size, k;
is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer)
|| (var->storage_modifiers & HLSL_STORAGE_UNIFORM)
|| ctx->cur_scope->annotations;
if (hlsl_type_is_shader(type))
is_default_values_initializer = false;
if (is_default_values_initializer)
{
@@ -2837,28 +2840,36 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
return initializers;
}
static bool func_is_compatible_match(struct hlsl_ctx *ctx,
const struct hlsl_ir_function_decl *decl, const struct parse_initializer *args)
static bool func_is_compatible_match(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *decl,
bool is_compile, const struct parse_initializer *args)
{
unsigned int i;
unsigned int i, k;
if (decl->parameters.count < args->args_count)
return false;
for (i = 0; i < args->args_count; ++i)
k = 0;
for (i = 0; i < decl->parameters.count; ++i)
{
if (!implicit_compatible_data_types(ctx, args->args[i]->data_type, decl->parameters.vars[i]->data_type))
if (is_compile && !(decl->parameters.vars[i]->storage_modifiers & HLSL_STORAGE_UNIFORM))
continue;
if (k >= args->args_count)
{
if (!decl->parameters.vars[i]->default_values)
return false;
return true;
}
if (!implicit_compatible_data_types(ctx, args->args[k]->data_type, decl->parameters.vars[i]->data_type))
return false;
++k;
}
if (args->args_count < decl->parameters.count && !decl->parameters.vars[args->args_count]->default_values)
if (k < args->args_count)
return false;
return true;
}
static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx,
const char *name, const struct parse_initializer *args,
const char *name, const struct parse_initializer *args, bool is_compile,
const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_function_decl *decl, *compatible_match = NULL;
@@ -2871,7 +2882,7 @@ static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx,
LIST_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry)
{
if (func_is_compatible_match(ctx, decl, args))
if (func_is_compatible_match(ctx, decl, is_compile, args))
{
if (compatible_match)
{
@@ -2892,26 +2903,35 @@ static struct hlsl_ir_node *hlsl_new_void_expr(struct hlsl_ctx *ctx, const struc
return hlsl_new_expr(ctx, HLSL_OP0_VOID, operands, ctx->builtin_types.Void, loc);
}
static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
const struct parse_initializer *args, const struct vkd3d_shader_location *loc)
static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx,
struct hlsl_ir_function_decl *func, const struct parse_initializer *args,
bool is_compile, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_node *call;
unsigned int i, j;
unsigned int i, j, k;
VKD3D_ASSERT(args->args_count <= func->parameters.count);
for (i = 0; i < args->args_count; ++i)
k = 0;
for (i = 0; i < func->parameters.count; ++i)
{
struct hlsl_ir_var *param = func->parameters.vars[i];
struct hlsl_ir_node *arg = args->args[i];
struct hlsl_ir_node *arg;
if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM))
continue;
if (k >= args->args_count)
break;
arg = args->args[k];
if (!hlsl_types_are_equal(arg->data_type, param->data_type))
{
struct hlsl_ir_node *cast;
if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc)))
return false;
args->args[i] = cast;
return NULL;
args->args[k] = cast;
arg = cast;
}
@@ -2920,13 +2940,15 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
struct hlsl_ir_node *store;
if (!(store = hlsl_new_simple_store(ctx, param, arg)))
return false;
return NULL;
hlsl_block_add_instr(args->instrs, store);
}
++k;
}
/* Add default values for the remaining parameters. */
for (i = args->args_count; i < func->parameters.count; ++i)
for (; i < func->parameters.count; ++i)
{
struct hlsl_ir_var *param = func->parameters.vars[i];
unsigned int comp_count = hlsl_type_component_count(param->data_type);
@@ -2934,6 +2956,9 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
VKD3D_ASSERT(param->default_values);
if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM))
continue;
hlsl_init_simple_deref_from_var(&param_deref, param);
for (j = 0; j < comp_count; ++j)
@@ -2947,20 +2972,23 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
{
value.u[0] = param->default_values[j].number;
if (!(comp = hlsl_new_constant(ctx, type, &value, loc)))
return false;
return NULL;
hlsl_block_add_instr(args->instrs, comp);
if (!hlsl_new_store_component(ctx, &store_block, &param_deref, j, comp))
return false;
return NULL;
hlsl_block_add_block(args->instrs, &store_block);
}
}
}
if (!(call = hlsl_new_call(ctx, func, loc)))
return false;
return NULL;
hlsl_block_add_instr(args->instrs, call);
if (is_compile)
return call;
for (i = 0; i < args->args_count; ++i)
{
struct hlsl_ir_var *param = func->parameters.vars[i];
@@ -2975,11 +3003,11 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
"Output argument to \"%s\" is const.", func->func->name);
if (!(load = hlsl_new_var_load(ctx, param, &arg->loc)))
return false;
return NULL;
hlsl_block_add_instr(args->instrs, &load->node);
if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &load->node))
return false;
return NULL;
}
}
@@ -3000,7 +3028,7 @@ static bool add_user_call(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *fu
hlsl_block_add_instr(args->instrs, expr);
}
return true;
return call;
}
static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx,
@@ -3167,7 +3195,7 @@ static bool write_acos_or_asin(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_acos(struct hlsl_ctx *ctx,
@@ -3316,7 +3344,7 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_atan(struct hlsl_ctx *ctx,
@@ -3509,7 +3537,7 @@ static bool write_cosh_or_sinh(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_cosh(struct hlsl_ctx *ctx,
@@ -3736,7 +3764,7 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_distance(struct hlsl_ctx *ctx,
@@ -3823,7 +3851,7 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_f16tof32(struct hlsl_ctx *ctx,
@@ -3928,7 +3956,7 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_ldexp(struct hlsl_ctx *ctx,
@@ -4031,7 +4059,7 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx,
if (!(func = hlsl_compile_internal_function(ctx, "lit", body)))
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_log(struct hlsl_ctx *ctx,
@@ -4334,7 +4362,7 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_round(struct hlsl_ctx *ctx,
@@ -4449,7 +4477,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_sqrt(struct hlsl_ctx *ctx,
@@ -4525,7 +4553,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx,
if (!func)
return false;
return add_user_call(ctx, func, params, loc);
return !!add_user_call(ctx, func, params, false, loc);
}
static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *params,
@@ -5004,9 +5032,9 @@ static struct hlsl_block *add_call(struct hlsl_ctx *ctx, const char *name,
struct intrinsic_function *intrinsic;
struct hlsl_ir_function_decl *decl;
if ((decl = find_function_call(ctx, name, args, loc)))
if ((decl = find_function_call(ctx, name, args, false, loc)))
{
if (!add_user_call(ctx, decl, args, loc))
if (!add_user_call(ctx, decl, args, false, loc))
goto fail;
}
else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
@@ -5062,6 +5090,53 @@ fail:
return NULL;
}
static struct hlsl_block *add_shader_compilation(struct hlsl_ctx *ctx, const char *profile_name,
const char *function_name, struct parse_initializer *args, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_node *compile, *call_to_compile = NULL;
struct hlsl_ir_function_decl *decl;
if (!ctx->in_state_block && ctx->cur_scope != ctx->globals)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE,
"Shader compilation statements must be in global scope or a state block.");
free_parse_initializer(args);
return NULL;
}
if (!(decl = find_function_call(ctx, function_name, args, true, loc)))
{
if (rb_get(&ctx->functions, function_name))
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED,
"No compatible \"%s\" declaration with %u uniform parameters found.",
function_name, args->args_count);
}
else
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED,
"Function \"%s\" is not defined.", function_name);
}
free_parse_initializer(args);
return NULL;
}
if (!(call_to_compile = add_user_call(ctx, decl, args, true, loc)))
{
free_parse_initializer(args);
return NULL;
}
if (!(compile = hlsl_new_compile(ctx, profile_name, &call_to_compile, 1, args->instrs, loc)))
{
free_parse_initializer(args);
return NULL;
}
free_parse_initializer(args);
return make_block(ctx, compile);
}
static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type,
struct parse_initializer *params, const struct vkd3d_shader_location *loc)
{
@@ -8393,6 +8468,18 @@ primary_expr:
{
$$ = $2;
}
| KW_COMPILE any_identifier var_identifier '(' func_arguments ')'
{
if (!($$ = add_shader_compilation(ctx, $2, $3, &$5, &@1)))
{
vkd3d_free($2);
vkd3d_free($3);
YYABORT;
}
vkd3d_free($2);
vkd3d_free($3);
}
| var_identifier '(' func_arguments ')'
{
if (!($$ = add_call(ctx, $1, &$3, &@1)))