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

@ -254,6 +254,45 @@ bool hlsl_type_is_resource(const struct hlsl_type *type)
} }
} }
bool hlsl_type_is_shader(const struct hlsl_type *type)
{
switch (type->class)
{
case HLSL_CLASS_ARRAY:
return hlsl_type_is_shader(type->e.array.type);
case HLSL_CLASS_COMPUTE_SHADER:
case HLSL_CLASS_DOMAIN_SHADER:
case HLSL_CLASS_GEOMETRY_SHADER:
case HLSL_CLASS_HULL_SHADER:
case HLSL_CLASS_PIXEL_SHADER:
case HLSL_CLASS_VERTEX_SHADER:
return true;
case HLSL_CLASS_SCALAR:
case HLSL_CLASS_VECTOR:
case HLSL_CLASS_MATRIX:
case HLSL_CLASS_STRUCT:
case HLSL_CLASS_DEPTH_STENCIL_STATE:
case HLSL_CLASS_DEPTH_STENCIL_VIEW:
case HLSL_CLASS_EFFECT_GROUP:
case HLSL_CLASS_PASS:
case HLSL_CLASS_RASTERIZER_STATE:
case HLSL_CLASS_RENDER_TARGET_VIEW:
case HLSL_CLASS_SAMPLER:
case HLSL_CLASS_STRING:
case HLSL_CLASS_TECHNIQUE:
case HLSL_CLASS_TEXTURE:
case HLSL_CLASS_UAV:
case HLSL_CLASS_CONSTANT_BUFFER:
case HLSL_CLASS_BLEND_STATE:
case HLSL_CLASS_VOID:
case HLSL_CLASS_NULL:
return false;
}
return false;
}
/* Only intended to be used for derefs (after copies have been lowered to components or vectors) or /* Only intended to be used for derefs (after copies have been lowered to components or vectors) or
* resources, since for both their data types span across a single regset. */ * resources, since for both their data types span across a single regset. */
static enum hlsl_regset type_get_regset(const struct hlsl_type *type) static enum hlsl_regset type_get_regset(const struct hlsl_type *type)
@ -1808,6 +1847,54 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned
return &swizzle->node; return &swizzle->node;
} }
struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name,
struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs,
const struct vkd3d_shader_location *loc)
{
const struct hlsl_profile_info *profile_info = NULL;
struct hlsl_ir_compile *compile;
struct hlsl_type *type = NULL;
unsigned int i;
if (!(profile_info = hlsl_get_target_info(profile_name)))
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Unknown profile \"%s\".", profile_name);
return NULL;
}
if (profile_info->type == VKD3D_SHADER_TYPE_PIXEL)
type = hlsl_get_type(ctx->cur_scope, "PixelShader", true, true);
else if (profile_info->type == VKD3D_SHADER_TYPE_VERTEX)
type = hlsl_get_type(ctx->cur_scope, "VertexShader", true, true);
if (!type)
{
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE, "Invalid profile \"%s\".", profile_name);
return NULL;
}
if (!(compile = hlsl_alloc(ctx, sizeof(*compile))))
return NULL;
init_node(&compile->node, HLSL_IR_COMPILE, type, loc);
compile->profile = profile_info;
hlsl_block_init(&compile->instrs);
hlsl_block_add_block(&compile->instrs, args_instrs);
compile->args_count = args_count;
if (!(compile->args = hlsl_alloc(ctx, sizeof(*compile->args) * args_count)))
{
vkd3d_free(compile);
return NULL;
}
for (i = 0; i < compile->args_count; ++i)
hlsl_src_from_node(&compile->args[i], args[i]);
return &compile->node;
}
struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name, struct hlsl_ir_node *hlsl_new_stateblock_constant(struct hlsl_ctx *ctx, const char *name,
struct vkd3d_shader_location *loc) struct vkd3d_shader_location *loc)
{ {
@ -2158,6 +2245,43 @@ static struct hlsl_ir_node *clone_index(struct hlsl_ctx *ctx, struct clone_instr
return dst; return dst;
} }
static struct hlsl_ir_node *clone_compile(struct hlsl_ctx *ctx,
struct clone_instr_map *map, struct hlsl_ir_compile *compile)
{
const char *profile_name = NULL;
struct hlsl_ir_node **args;
struct hlsl_ir_node *node;
struct hlsl_block block;
unsigned int i;
if (!(clone_block(ctx, &block, &compile->instrs, map)))
return NULL;
if (!(args = hlsl_alloc(ctx, sizeof(*args) * compile->args_count)))
{
hlsl_block_cleanup(&block);
return NULL;
}
for (i = 0; i < compile->args_count; ++i)
{
args[i] = map_instr(map, compile->args[i].node);
VKD3D_ASSERT(args[i]);
}
if (compile->profile)
profile_name = compile->profile->name;
if (!(node = hlsl_new_compile(ctx, profile_name, args, compile->args_count, &block, &compile->node.loc)))
{
hlsl_block_cleanup(&block);
vkd3d_free(args);
return NULL;
}
vkd3d_free(args);
return node;
}
static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx, static struct hlsl_ir_node *clone_stateblock_constant(struct hlsl_ctx *ctx,
struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant) struct clone_instr_map *map, struct hlsl_ir_stateblock_constant *constant)
{ {
@ -2300,6 +2424,9 @@ static struct hlsl_ir_node *clone_instr(struct hlsl_ctx *ctx,
case HLSL_IR_SWIZZLE: case HLSL_IR_SWIZZLE:
return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr)); return clone_swizzle(ctx, map, hlsl_ir_swizzle(instr));
case HLSL_IR_COMPILE:
return clone_compile(ctx, map, hlsl_ir_compile(instr));
case HLSL_IR_STATEBLOCK_CONSTANT: case HLSL_IR_STATEBLOCK_CONSTANT:
return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr)); return clone_stateblock_constant(ctx, map, hlsl_ir_stateblock_constant(instr));
@ -2717,6 +2844,8 @@ const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type)
[HLSL_IR_STORE ] = "HLSL_IR_STORE", [HLSL_IR_STORE ] = "HLSL_IR_STORE",
[HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH", [HLSL_IR_SWITCH ] = "HLSL_IR_SWITCH",
[HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE", [HLSL_IR_SWIZZLE ] = "HLSL_IR_SWIZZLE",
[HLSL_IR_COMPILE] = "HLSL_IR_COMPILE",
[HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT", [HLSL_IR_STATEBLOCK_CONSTANT] = "HLSL_IR_STATEBLOCK_CONSTANT",
[HLSL_IR_VSIR_INSTRUCTION_REF] = "HLSL_IR_VSIR_INSTRUCTION_REF", [HLSL_IR_VSIR_INSTRUCTION_REF] = "HLSL_IR_VSIR_INSTRUCTION_REF",
}; };
@ -3166,6 +3295,25 @@ static void dump_ir_index(struct vkd3d_string_buffer *buffer, const struct hlsl_
vkd3d_string_buffer_printf(buffer, "]"); vkd3d_string_buffer_printf(buffer, "]");
} }
static void dump_ir_compile(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer,
const struct hlsl_ir_compile *compile)
{
unsigned int i;
vkd3d_string_buffer_printf(buffer, "compile %s {\n", compile->profile->name);
dump_block(ctx, buffer, &compile->instrs);
vkd3d_string_buffer_printf(buffer, " %10s } (", "");
for (i = 0; i < compile->args_count; ++i)
{
dump_src(buffer, &compile->args[i]);
if (i + 1 < compile->args_count)
vkd3d_string_buffer_printf(buffer, ", ");
}
vkd3d_string_buffer_printf(buffer, ")");
}
static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer, static void dump_ir_stateblock_constant(struct vkd3d_string_buffer *buffer,
const struct hlsl_ir_stateblock_constant *constant) const struct hlsl_ir_stateblock_constant *constant)
{ {
@ -3265,6 +3413,10 @@ static void dump_instr(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer,
dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr)); dump_ir_swizzle(buffer, hlsl_ir_swizzle(instr));
break; break;
case HLSL_IR_COMPILE:
dump_ir_compile(ctx, buffer, hlsl_ir_compile(instr));
break;
case HLSL_IR_STATEBLOCK_CONSTANT: case HLSL_IR_STATEBLOCK_CONSTANT:
dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr)); dump_ir_stateblock_constant(buffer, hlsl_ir_stateblock_constant(instr));
break; break;
@ -3484,6 +3636,17 @@ static void free_ir_index(struct hlsl_ir_index *index)
vkd3d_free(index); vkd3d_free(index);
} }
static void free_ir_compile(struct hlsl_ir_compile *compile)
{
unsigned int i;
for (i = 0; i < compile->args_count; ++i)
hlsl_src_remove(&compile->args[i]);
hlsl_block_cleanup(&compile->instrs);
vkd3d_free(compile);
}
static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant) static void free_ir_stateblock_constant(struct hlsl_ir_stateblock_constant *constant)
{ {
vkd3d_free(constant->name); vkd3d_free(constant->name);
@ -3552,6 +3715,10 @@ void hlsl_free_instr(struct hlsl_ir_node *node)
free_ir_switch(hlsl_ir_switch(node)); free_ir_switch(hlsl_ir_switch(node));
break; break;
case HLSL_IR_COMPILE:
free_ir_compile(hlsl_ir_compile(node));
break;
case HLSL_IR_STATEBLOCK_CONSTANT: case HLSL_IR_STATEBLOCK_CONSTANT:
free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node)); free_ir_stateblock_constant(hlsl_ir_stateblock_constant(node));
break; break;

View File

@ -324,6 +324,8 @@ enum hlsl_ir_node_type
HLSL_IR_STORE, HLSL_IR_STORE,
HLSL_IR_SWIZZLE, HLSL_IR_SWIZZLE,
HLSL_IR_SWITCH, HLSL_IR_SWITCH,
HLSL_IR_COMPILE,
HLSL_IR_STATEBLOCK_CONSTANT, HLSL_IR_STATEBLOCK_CONSTANT,
HLSL_IR_VSIR_INSTRUCTION_REF, HLSL_IR_VSIR_INSTRUCTION_REF,
@ -864,6 +866,27 @@ struct hlsl_ir_string_constant
char *string; char *string;
}; };
/* Represents shader compilation call for effects, such as "CompileShader()".
*
* Unlike hlsl_ir_call, it is not flattened, thus, it keeps track of its
* arguments and maintains its own instruction block. */
struct hlsl_ir_compile
{
struct hlsl_ir_node node;
/* Special field to store the profile argument. */
const struct hlsl_profile_info *profile;
/* Block containing the instructions required by the arguments of the
* compilation call. */
struct hlsl_block instrs;
/* Arguments to the compilation call. For a "compile" or "CompileShader()"
* args[0] is an hlsl_ir_call to the specified function. */
struct hlsl_src *args;
unsigned int args_count;
};
/* Stateblock constants are undeclared values found on state blocks or technique passes descriptions, /* Stateblock constants are undeclared values found on state blocks or technique passes descriptions,
* that do not concern regular pixel, vertex, or compute shaders, except for parsing. */ * that do not concern regular pixel, vertex, or compute shaders, except for parsing. */
struct hlsl_ir_stateblock_constant struct hlsl_ir_stateblock_constant
@ -1170,6 +1193,12 @@ static inline struct hlsl_ir_switch *hlsl_ir_switch(const struct hlsl_ir_node *n
return CONTAINING_RECORD(node, struct hlsl_ir_switch, node); return CONTAINING_RECORD(node, struct hlsl_ir_switch, node);
} }
static inline struct hlsl_ir_compile *hlsl_ir_compile(const struct hlsl_ir_node *node)
{
VKD3D_ASSERT(node->type == HLSL_IR_COMPILE);
return CONTAINING_RECORD(node, struct hlsl_ir_compile, node);
}
static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node) static inline struct hlsl_ir_stateblock_constant *hlsl_ir_stateblock_constant(const struct hlsl_ir_node *node)
{ {
VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT); VKD3D_ASSERT(node->type == HLSL_IR_STATEBLOCK_CONSTANT);
@ -1455,6 +1484,9 @@ bool hlsl_index_is_noncontiguous(struct hlsl_ir_index *index);
bool hlsl_index_is_resource_access(struct hlsl_ir_index *index); bool hlsl_index_is_resource_access(struct hlsl_ir_index *index);
bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index); bool hlsl_index_chain_has_resource_access(struct hlsl_ir_index *index);
struct hlsl_ir_node *hlsl_new_compile(struct hlsl_ctx *ctx, const char *profile_name,
struct hlsl_ir_node **args, unsigned int args_count, struct hlsl_block *args_instrs,
const struct vkd3d_shader_location *loc);
struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val, struct hlsl_ir_node *hlsl_new_index(struct hlsl_ctx *ctx, struct hlsl_ir_node *val,
struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc); struct hlsl_ir_node *idx, const struct vkd3d_shader_location *loc);
struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx, struct hlsl_ir_node *hlsl_new_loop(struct hlsl_ctx *ctx,
@ -1523,6 +1555,7 @@ unsigned int hlsl_type_minor_size(const struct hlsl_type *type);
unsigned int hlsl_type_major_size(const struct hlsl_type *type); unsigned int hlsl_type_major_size(const struct hlsl_type *type);
unsigned int hlsl_type_element_count(const struct hlsl_type *type); unsigned int hlsl_type_element_count(const struct hlsl_type *type);
bool hlsl_type_is_resource(const struct hlsl_type *type); bool hlsl_type_is_resource(const struct hlsl_type *type);
bool hlsl_type_is_shader(const struct hlsl_type *type);
unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); unsigned int hlsl_type_get_sm4_offset(const struct hlsl_type *type, unsigned int offset);
bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2); bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2);

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_LOAD:
case HLSL_IR_RESOURCE_STORE: case HLSL_IR_RESOURCE_STORE:
case HLSL_IR_SWITCH: case HLSL_IR_SWITCH:
case HLSL_IR_COMPILE:
case HLSL_IR_STATEBLOCK_CONSTANT: case HLSL_IR_STATEBLOCK_CONSTANT:
hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, hlsl_error(ctx, &node->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"Expected literal expression."); "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) if (v->initializer.args_count)
{ {
unsigned int store_index = 0;
bool is_default_values_initializer; bool is_default_values_initializer;
unsigned int store_index = 0;
unsigned int size, k; unsigned int size, k;
is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer) is_default_values_initializer = (ctx->cur_buffer != ctx->globals_buffer)
|| (var->storage_modifiers & HLSL_STORAGE_UNIFORM) || (var->storage_modifiers & HLSL_STORAGE_UNIFORM)
|| ctx->cur_scope->annotations; || ctx->cur_scope->annotations;
if (hlsl_type_is_shader(type))
is_default_values_initializer = false;
if (is_default_values_initializer) if (is_default_values_initializer)
{ {
@ -2837,28 +2840,36 @@ static struct hlsl_block *initialize_vars(struct hlsl_ctx *ctx, struct list *var
return initializers; return initializers;
} }
static bool func_is_compatible_match(struct hlsl_ctx *ctx, static bool func_is_compatible_match(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *decl,
const struct hlsl_ir_function_decl *decl, const struct parse_initializer *args) bool is_compile, const struct parse_initializer *args)
{ {
unsigned int i; unsigned int i, k;
if (decl->parameters.count < args->args_count) k = 0;
return false; for (i = 0; i < decl->parameters.count; ++i)
for (i = 0; i < args->args_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 false;
return true;
} }
if (args->args_count < decl->parameters.count && !decl->parameters.vars[args->args_count]->default_values) if (!implicit_compatible_data_types(ctx, args->args[k]->data_type, decl->parameters.vars[i]->data_type))
return false; return false;
++k;
}
if (k < args->args_count)
return false;
return true; return true;
} }
static struct hlsl_ir_function_decl *find_function_call(struct hlsl_ctx *ctx, 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) const struct vkd3d_shader_location *loc)
{ {
struct hlsl_ir_function_decl *decl, *compatible_match = NULL; 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) 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) 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); 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, static struct hlsl_ir_node *add_user_call(struct hlsl_ctx *ctx,
const struct parse_initializer *args, const struct vkd3d_shader_location *loc) 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; struct hlsl_ir_node *call;
unsigned int i, j; unsigned int i, j, k;
VKD3D_ASSERT(args->args_count <= func->parameters.count); 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_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)) if (!hlsl_types_are_equal(arg->data_type, param->data_type))
{ {
struct hlsl_ir_node *cast; struct hlsl_ir_node *cast;
if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc))) if (!(cast = add_cast(ctx, args->instrs, arg, param->data_type, &arg->loc)))
return false; return NULL;
args->args[i] = cast; args->args[k] = cast;
arg = 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; struct hlsl_ir_node *store;
if (!(store = hlsl_new_simple_store(ctx, param, arg))) if (!(store = hlsl_new_simple_store(ctx, param, arg)))
return false; return NULL;
hlsl_block_add_instr(args->instrs, store); hlsl_block_add_instr(args->instrs, store);
} }
++k;
} }
/* Add default values for the remaining parameters. */ /* 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]; struct hlsl_ir_var *param = func->parameters.vars[i];
unsigned int comp_count = hlsl_type_component_count(param->data_type); 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); VKD3D_ASSERT(param->default_values);
if (is_compile && !(param->storage_modifiers & HLSL_STORAGE_UNIFORM))
continue;
hlsl_init_simple_deref_from_var(&param_deref, param); hlsl_init_simple_deref_from_var(&param_deref, param);
for (j = 0; j < comp_count; ++j) 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; value.u[0] = param->default_values[j].number;
if (!(comp = hlsl_new_constant(ctx, type, &value, loc))) if (!(comp = hlsl_new_constant(ctx, type, &value, loc)))
return false; return NULL;
hlsl_block_add_instr(args->instrs, comp); hlsl_block_add_instr(args->instrs, comp);
if (!hlsl_new_store_component(ctx, &store_block, &param_deref, j, 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); hlsl_block_add_block(args->instrs, &store_block);
} }
} }
} }
if (!(call = hlsl_new_call(ctx, func, loc))) if (!(call = hlsl_new_call(ctx, func, loc)))
return false; return NULL;
hlsl_block_add_instr(args->instrs, call); hlsl_block_add_instr(args->instrs, call);
if (is_compile)
return call;
for (i = 0; i < args->args_count; ++i) for (i = 0; i < args->args_count; ++i)
{ {
struct hlsl_ir_var *param = func->parameters.vars[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); "Output argument to \"%s\" is const.", func->func->name);
if (!(load = hlsl_new_var_load(ctx, param, &arg->loc))) if (!(load = hlsl_new_var_load(ctx, param, &arg->loc)))
return false; return NULL;
hlsl_block_add_instr(args->instrs, &load->node); hlsl_block_add_instr(args->instrs, &load->node);
if (!add_assignment(ctx, args->instrs, arg, ASSIGN_OP_ASSIGN, &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); hlsl_block_add_instr(args->instrs, expr);
} }
return true; return call;
} }
static struct hlsl_ir_node *intrinsic_float_convert_arg(struct hlsl_ctx *ctx, 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) if (!func)
return false; 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, static bool intrinsic_acos(struct hlsl_ctx *ctx,
@ -3316,7 +3344,7 @@ static bool write_atan_or_atan2(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, static bool intrinsic_atan(struct hlsl_ctx *ctx,
@ -3509,7 +3537,7 @@ static bool write_cosh_or_sinh(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, static bool intrinsic_cosh(struct hlsl_ctx *ctx,
@ -3736,7 +3764,7 @@ static bool intrinsic_determinant(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, static bool intrinsic_distance(struct hlsl_ctx *ctx,
@ -3823,7 +3851,7 @@ static bool intrinsic_faceforward(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, static bool intrinsic_f16tof32(struct hlsl_ctx *ctx,
@ -3928,7 +3956,7 @@ static bool intrinsic_fwidth(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, 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))) if (!(func = hlsl_compile_internal_function(ctx, "lit", body)))
return false; 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, static bool intrinsic_log(struct hlsl_ctx *ctx,
@ -4334,7 +4362,7 @@ static bool intrinsic_refract(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, static bool intrinsic_round(struct hlsl_ctx *ctx,
@ -4449,7 +4477,7 @@ static bool intrinsic_smoothstep(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, static bool intrinsic_sqrt(struct hlsl_ctx *ctx,
@ -4525,7 +4553,7 @@ static bool intrinsic_tanh(struct hlsl_ctx *ctx,
if (!func) if (!func)
return false; 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, 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 intrinsic_function *intrinsic;
struct hlsl_ir_function_decl *decl; 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; goto fail;
} }
else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions), else if ((intrinsic = bsearch(name, intrinsic_functions, ARRAY_SIZE(intrinsic_functions),
@ -5062,6 +5090,53 @@ fail:
return NULL; 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, static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type,
struct parse_initializer *params, const struct vkd3d_shader_location *loc) struct parse_initializer *params, const struct vkd3d_shader_location *loc)
{ {
@ -8393,6 +8468,18 @@ primary_expr:
{ {
$$ = $2; $$ = $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 ')' | var_identifier '(' func_arguments ')'
{ {
if (!($$ = add_call(ctx, $1, &$3, &@1))) if (!($$ = add_call(ctx, $1, &$3, &@1)))

View File

@ -4050,6 +4050,7 @@ static bool dce(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
switch (instr->type) switch (instr->type)
{ {
case HLSL_IR_CONSTANT: case HLSL_IR_CONSTANT:
case HLSL_IR_COMPILE:
case HLSL_IR_EXPR: case HLSL_IR_EXPR:
case HLSL_IR_INDEX: case HLSL_IR_INDEX:
case HLSL_IR_LOAD: case HLSL_IR_LOAD:
@ -4343,6 +4344,9 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop
case HLSL_IR_CONSTANT: case HLSL_IR_CONSTANT:
case HLSL_IR_STRING_CONSTANT: case HLSL_IR_STRING_CONSTANT:
break; break;
case HLSL_IR_COMPILE:
/* Compile calls are skipped as they are only relevent to effects. */
break;
} }
} }
} }

View File

@ -152,6 +152,8 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_HLSL_UNKNOWN_MODIFIER = 5030, VKD3D_SHADER_ERROR_HLSL_UNKNOWN_MODIFIER = 5030,
VKD3D_SHADER_ERROR_HLSL_INVALID_STATE_BLOCK_ENTRY = 5031, VKD3D_SHADER_ERROR_HLSL_INVALID_STATE_BLOCK_ENTRY = 5031,
VKD3D_SHADER_ERROR_HLSL_FAILED_FORCED_UNROLL = 5032, VKD3D_SHADER_ERROR_HLSL_FAILED_FORCED_UNROLL = 5032,
VKD3D_SHADER_ERROR_HLSL_INVALID_PROFILE = 5033,
VKD3D_SHADER_ERROR_HLSL_MISPLACED_COMPILE = 5034,
VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300, VKD3D_SHADER_WARNING_HLSL_IMPLICIT_TRUNCATION = 5300,
VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301, VKD3D_SHADER_WARNING_HLSL_DIVISION_BY_ZERO = 5301,

View File

@ -1,5 +1,5 @@
% Test special "compile" keyword syntax to compile pixel and vertex shaders % Test special "compile" keyword syntax to compile pixel and vertex shaders
[pixel shader todo] [pixel shader]
float4 fun() : sv_target float4 fun() : sv_target
{ {
return 0; return 0;
@ -13,7 +13,7 @@ sampler sam
float4 main() : sv_target { return 0; } float4 main() : sv_target { return 0; }
[pixel shader todo] [pixel shader]
float4 fun() : sv_target float4 fun() : sv_target
{ {
return 0; return 0;
@ -31,7 +31,7 @@ float4 main() : sv_target { return 0; }
% Only uniform arguments are expected, even if undefined identifiers are used. % Only uniform arguments are expected, even if undefined identifiers are used.
[pixel shader todo] [pixel shader]
float4 fun(uniform float4 a, float4 b, uniform float4 c) : sv_target float4 fun(uniform float4 a, float4 b, uniform float4 c) : sv_target
{ {
return a + b + c; return a + b + c;
@ -185,7 +185,7 @@ float4 main() : sv_target
% Default values are allowed for uniform variables. % Default values are allowed for uniform variables.
[pixel shader todo fail(sm>=6)] [pixel shader fail(sm>=6)]
float4 fun(uniform float4 a, uniform float4 b = {1, 2, 3, 4}) : sv_target float4 fun(uniform float4 a, uniform float4 b = {1, 2, 3, 4}) : sv_target
{ {
return 8*a + b; return 8*a + b;
@ -202,7 +202,7 @@ technique10 T1
float4 main() : sv_target { return 0; } float4 main() : sv_target { return 0; }
[pixel shader todo fail(sm>=6)] [pixel shader fail(sm>=6)]
float4 fun(float4 a : COLOR0 = {-1, -2, -3, -4}, uniform float4 b = {1, 2, 3, 4}) : sv_target float4 fun(float4 a : COLOR0 = {-1, -2, -3, -4}, uniform float4 b = {1, 2, 3, 4}) : sv_target
{ {
return 8*a + b; return 8*a + b;