d3dcompiler: Properly support function overloads.

This commit is contained in:
Matteo Bruni 2012-10-11 19:48:48 +02:00 committed by Alexandre Julliard
parent deb00c9460
commit 6897f9aa35
3 changed files with 220 additions and 39 deletions

View File

@ -752,10 +752,19 @@ struct hlsl_ir_var
struct hlsl_var_allocation *allocation; struct hlsl_var_allocation *allocation;
}; };
struct hlsl_ir_function
{
struct wine_rb_entry entry;
const char *name;
struct wine_rb_tree overloads;
BOOL intrinsic;
};
struct hlsl_ir_function_decl struct hlsl_ir_function_decl
{ {
struct hlsl_ir_node node; struct hlsl_ir_node node;
const char *name; struct wine_rb_entry entry;
struct hlsl_ir_function *func;
const char *semantic; const char *semantic;
struct list *parameters; struct list *parameters;
struct list *body; struct list *body;
@ -960,6 +969,12 @@ struct parse_variable_def
struct list *initializer; struct list *initializer;
}; };
struct parse_function
{
char *name;
struct hlsl_ir_function_decl *decl;
};
struct parse_if_body struct parse_if_body
{ {
struct list *then_instrs; struct list *then_instrs;
@ -1004,7 +1019,7 @@ struct hlsl_parse_ctx
struct list scopes; struct list scopes;
struct list types; struct list types;
struct list functions; struct wine_rb_tree functions;
enum hlsl_matrix_majority matrix_majority; enum hlsl_matrix_majority matrix_majority;
}; };
@ -1127,18 +1142,21 @@ struct hlsl_ir_node *make_assignment(struct hlsl_ir_node *left, enum parse_assig
DWORD writemask, struct hlsl_ir_node *right) DECLSPEC_HIDDEN; DWORD writemask, struct hlsl_ir_node *right) DECLSPEC_HIDDEN;
void push_scope(struct hlsl_parse_ctx *ctx) DECLSPEC_HIDDEN; void push_scope(struct hlsl_parse_ctx *ctx) DECLSPEC_HIDDEN;
BOOL pop_scope(struct hlsl_parse_ctx *ctx) DECLSPEC_HIDDEN; BOOL pop_scope(struct hlsl_parse_ctx *ctx) DECLSPEC_HIDDEN;
struct hlsl_ir_function_decl *new_func_decl(const char *name, struct hlsl_type *return_type, struct list *parameters) DECLSPEC_HIDDEN; struct hlsl_ir_function_decl *new_func_decl(struct hlsl_type *return_type, struct list *parameters) DECLSPEC_HIDDEN;
void init_functions_tree(struct wine_rb_tree *funcs) DECLSPEC_HIDDEN;
void add_function_decl(struct wine_rb_tree *funcs, char *name, struct hlsl_ir_function_decl *decl,
BOOL intrinsic) DECLSPEC_HIDDEN;
struct bwriter_shader *parse_hlsl_shader(const char *text, enum shader_type type, DWORD major, DWORD minor, struct bwriter_shader *parse_hlsl_shader(const char *text, enum shader_type type, DWORD major, DWORD minor,
const char *entrypoint, char **messages) DECLSPEC_HIDDEN; const char *entrypoint, char **messages) DECLSPEC_HIDDEN;
const char *debug_hlsl_type(const struct hlsl_type *type) DECLSPEC_HIDDEN; const char *debug_hlsl_type(const struct hlsl_type *type) DECLSPEC_HIDDEN;
const char *debug_modifiers(DWORD modifiers) DECLSPEC_HIDDEN; const char *debug_modifiers(DWORD modifiers) DECLSPEC_HIDDEN;
void debug_dump_ir_function(const struct hlsl_ir_function_decl *func) DECLSPEC_HIDDEN; void debug_dump_ir_function_decl(const struct hlsl_ir_function_decl *func) DECLSPEC_HIDDEN;
void free_hlsl_type(struct hlsl_type *type) DECLSPEC_HIDDEN; void free_hlsl_type(struct hlsl_type *type) DECLSPEC_HIDDEN;
void free_instr(struct hlsl_ir_node *node) DECLSPEC_HIDDEN; void free_instr(struct hlsl_ir_node *node) DECLSPEC_HIDDEN;
void free_instr_list(struct list *list) DECLSPEC_HIDDEN; void free_instr_list(struct list *list) DECLSPEC_HIDDEN;
void free_function(struct hlsl_ir_function_decl *func) DECLSPEC_HIDDEN; void free_function_rb(struct wine_rb_entry *entry, void *context) DECLSPEC_HIDDEN;
#define MAKE_TAG(ch0, ch1, ch2, ch3) \ #define MAKE_TAG(ch0, ch1, ch2, ch3) \

View File

@ -825,7 +825,7 @@ static BOOL add_typedef(DWORD modifiers, struct hlsl_type *orig_type, struct lis
struct hlsl_ir_var *var; struct hlsl_ir_var *var;
struct hlsl_ir_node *instr; struct hlsl_ir_node *instr;
struct list *list; struct list *list;
struct hlsl_ir_function_decl *function; struct parse_function function;
struct parse_parameter parameter; struct parse_parameter parameter;
struct parse_variable_def *variable_def; struct parse_variable_def *variable_def;
struct parse_if_body if_body; struct parse_if_body if_body;
@ -1000,8 +1000,8 @@ hlsl_prog: /* empty */
} }
| hlsl_prog func_declaration | hlsl_prog func_declaration
{ {
FIXME("Check that the function doesn't conflict with an already declared one.\n"); TRACE("Adding function '%s' to the function list.\n", $2.name);
list_add_tail(&hlsl_ctx.functions, &$2->node.entry); add_function_decl(&hlsl_ctx.functions, $2.name, $2.decl, FALSE);
} }
| hlsl_prog declaration_statement | hlsl_prog declaration_statement
{ {
@ -1125,14 +1125,14 @@ field: var_modifiers type variables_def ';'
func_declaration: func_prototype compound_statement func_declaration: func_prototype compound_statement
{ {
TRACE("Function %s parsed.\n", $1->name); TRACE("Function %s parsed.\n", $1.name);
$$ = $1; $$ = $1;
$$->body = $2; $$.decl->body = $2;
pop_scope(&hlsl_ctx); pop_scope(&hlsl_ctx);
} }
| func_prototype ';' | func_prototype ';'
{ {
TRACE("Function prototype for %s.\n", $1->name); TRACE("Function prototype for %s.\n", $1.name);
$$ = $1; $$ = $1;
pop_scope(&hlsl_ctx); pop_scope(&hlsl_ctx);
} }
@ -1151,13 +1151,15 @@ func_prototype: var_modifiers type var_identifier '(' parameters ')' s
HLSL_LEVEL_ERROR, "void function with a semantic"); HLSL_LEVEL_ERROR, "void function with a semantic");
} }
$$ = new_func_decl($3, $2, $5); $$.decl = new_func_decl($2, $5);
if (!$$) if (!$$.decl)
{ {
ERR("Out of memory.\n"); ERR("Out of memory.\n");
return -1; return -1;
} }
$$->semantic = $7; $$.name = $3;
$$.decl->semantic = $7;
set_location(&$$.decl->node.loc, &@3);
} }
compound_statement: '{' '}' compound_statement: '{' '}'
@ -2330,10 +2332,22 @@ static DWORD add_modifier(DWORD modifiers, DWORD mod, const struct YYLTYPE *loc)
return modifiers | mod; return modifiers | mod;
} }
static void dump_function_decl(struct wine_rb_entry *entry, void *context)
{
struct hlsl_ir_function_decl *func = WINE_RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
if (func->body)
debug_dump_ir_function_decl(func);
}
static void dump_function(struct wine_rb_entry *entry, void *context)
{
struct hlsl_ir_function *func = WINE_RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
wine_rb_for_each_entry(&func->overloads, dump_function_decl, NULL);
}
struct bwriter_shader *parse_hlsl(enum shader_type type, DWORD major, DWORD minor, struct bwriter_shader *parse_hlsl(enum shader_type type, DWORD major, DWORD minor,
const char *entrypoint, char **messages) const char *entrypoint, char **messages)
{ {
struct hlsl_ir_function_decl *function, *next_function;
struct hlsl_scope *scope, *next_scope; struct hlsl_scope *scope, *next_scope;
struct hlsl_type *hlsl_type, *next_type; struct hlsl_type *hlsl_type, *next_type;
struct hlsl_ir_var *var, *next_var; struct hlsl_ir_var *var, *next_var;
@ -2351,7 +2365,7 @@ struct bwriter_shader *parse_hlsl(enum shader_type type, DWORD major, DWORD mino
hlsl_ctx.matrix_majority = HLSL_COLUMN_MAJOR; hlsl_ctx.matrix_majority = HLSL_COLUMN_MAJOR;
list_init(&hlsl_ctx.scopes); list_init(&hlsl_ctx.scopes);
list_init(&hlsl_ctx.types); list_init(&hlsl_ctx.types);
list_init(&hlsl_ctx.functions); init_functions_tree(&hlsl_ctx.functions);
push_scope(&hlsl_ctx); push_scope(&hlsl_ctx);
hlsl_ctx.globals = hlsl_ctx.cur_scope; hlsl_ctx.globals = hlsl_ctx.cur_scope;
@ -2361,14 +2375,8 @@ struct bwriter_shader *parse_hlsl(enum shader_type type, DWORD major, DWORD mino
if (TRACE_ON(hlsl_parser)) if (TRACE_ON(hlsl_parser))
{ {
struct hlsl_ir_function_decl *func;
TRACE("IR dump.\n"); TRACE("IR dump.\n");
LIST_FOR_EACH_ENTRY(func, &hlsl_ctx.functions, struct hlsl_ir_function_decl, node.entry) wine_rb_for_each_entry(&hlsl_ctx.functions, dump_function, NULL);
{
if (func->body)
debug_dump_ir_function(func);
}
} }
TRACE("Compilation status = %d\n", hlsl_ctx.status); TRACE("Compilation status = %d\n", hlsl_ctx.status);
@ -2390,8 +2398,7 @@ struct bwriter_shader *parse_hlsl(enum shader_type type, DWORD major, DWORD mino
d3dcompiler_free(hlsl_ctx.source_files); d3dcompiler_free(hlsl_ctx.source_files);
TRACE("Freeing functions IR.\n"); TRACE("Freeing functions IR.\n");
LIST_FOR_EACH_ENTRY_SAFE(function, next_function, &hlsl_ctx.functions, struct hlsl_ir_function_decl, node.entry) wine_rb_destroy(&hlsl_ctx.functions, free_function_rb, NULL);
free_function(function);
TRACE("Freeing variables.\n"); TRACE("Freeing variables.\n");
LIST_FOR_EACH_ENTRY_SAFE(scope, next_scope, &hlsl_ctx.scopes, struct hlsl_scope, entry) LIST_FOR_EACH_ENTRY_SAFE(scope, next_scope, &hlsl_ctx.scopes, struct hlsl_scope, entry)

View File

@ -878,14 +878,7 @@ struct hlsl_type *get_type(struct hlsl_scope *scope, const char *name, BOOL recu
BOOL find_function(const char *name) BOOL find_function(const char *name)
{ {
struct hlsl_ir_function_decl *func; return wine_rb_get(&hlsl_ctx.functions, name) != NULL;
LIST_FOR_EACH_ENTRY(func, &hlsl_ctx.functions, struct hlsl_ir_function_decl, node.entry)
{
if (!strcmp(func->name, name))
return TRUE;
}
return FALSE;
} }
unsigned int components_count_type(struct hlsl_type *type) unsigned int components_count_type(struct hlsl_type *type)
@ -1762,7 +1755,7 @@ BOOL pop_scope(struct hlsl_parse_ctx *ctx)
return TRUE; return TRUE;
} }
struct hlsl_ir_function_decl *new_func_decl(const char *name, struct hlsl_type *return_type, struct list *parameters) struct hlsl_ir_function_decl *new_func_decl(struct hlsl_type *return_type, struct list *parameters)
{ {
struct hlsl_ir_function_decl *decl; struct hlsl_ir_function_decl *decl;
@ -1774,12 +1767,117 @@ struct hlsl_ir_function_decl *new_func_decl(const char *name, struct hlsl_type *
} }
decl->node.type = HLSL_IR_FUNCTION_DECL; decl->node.type = HLSL_IR_FUNCTION_DECL;
decl->node.data_type = return_type; decl->node.data_type = return_type;
decl->name = name;
decl->parameters = parameters; decl->parameters = parameters;
return decl; return decl;
} }
static int compare_param_hlsl_types(const struct hlsl_type *t1, const struct hlsl_type *t2)
{
if (t1->type != t2->type)
{
if (!((t1->type == HLSL_CLASS_SCALAR && t2->type == HLSL_CLASS_VECTOR)
|| (t1->type == HLSL_CLASS_VECTOR && t2->type == HLSL_CLASS_SCALAR)))
return t1->type - t2->type;
}
if (t1->base_type != t2->base_type)
return t1->base_type - t2->base_type;
if (t1->base_type == HLSL_TYPE_SAMPLER && t1->sampler_dim != t2->sampler_dim)
return t1->sampler_dim - t2->sampler_dim;
if (t1->dimx != t2->dimx)
return t1->dimx - t2->dimx;
if (t1->dimy != t2->dimy)
return t1->dimx - t2->dimx;
if (t1->type == HLSL_CLASS_STRUCT)
{
struct list *t1cur, *t2cur;
struct hlsl_struct_field *t1field, *t2field;
int r;
t1cur = list_head(t1->e.elements);
t2cur = list_head(t2->e.elements);
while (t1cur && t2cur)
{
t1field = LIST_ENTRY(t1cur, struct hlsl_struct_field, entry);
t2field = LIST_ENTRY(t2cur, struct hlsl_struct_field, entry);
if ((r = compare_param_hlsl_types(t1field->type, t2field->type)))
return r;
if ((r = strcmp(t1field->name, t2field->name)))
return r;
t1cur = list_next(t1->e.elements, t1cur);
t2cur = list_next(t2->e.elements, t2cur);
}
if (t1cur != t2cur)
return t1cur ? 1 : -1;
return 0;
}
if (t1->type == HLSL_CLASS_ARRAY)
{
if (t1->e.array.elements_count != t2->e.array.elements_count)
return t1->e.array.elements_count - t2->e.array.elements_count;
return compare_param_hlsl_types(t1->e.array.type, t2->e.array.type);
}
return 0;
}
static int compare_function_decl_rb(const void *key, const struct wine_rb_entry *entry)
{
const struct list *params = (const struct list *)key;
const struct hlsl_ir_function_decl *decl = WINE_RB_ENTRY_VALUE(entry, const struct hlsl_ir_function_decl, entry);
int params_count = params ? list_count(params) : 0;
int decl_params_count = decl->parameters ? list_count(decl->parameters) : 0;
int r;
struct list *p1cur, *p2cur;
if (params_count != decl_params_count)
return params_count - decl_params_count;
p1cur = params ? list_head(params) : NULL;
p2cur = decl->parameters ? list_head(decl->parameters) : NULL;
while (p1cur && p2cur)
{
struct hlsl_ir_var *p1, *p2;
p1 = LIST_ENTRY(p1cur, struct hlsl_ir_var, node.entry);
p2 = LIST_ENTRY(p2cur, struct hlsl_ir_var, node.entry);
if ((r = compare_param_hlsl_types(p1->node.data_type, p2->node.data_type)))
return r;
p1cur = list_next(params, p1cur);
p2cur = list_next(decl->parameters, p2cur);
}
return 0;
}
static const struct wine_rb_functions hlsl_ir_function_decl_rb_funcs =
{
d3dcompiler_alloc_rb,
d3dcompiler_realloc_rb,
d3dcompiler_free_rb,
compare_function_decl_rb,
};
static int compare_function_rb(const void *key, const struct wine_rb_entry *entry)
{
const char *name = (const char *)key;
const struct hlsl_ir_function *func = WINE_RB_ENTRY_VALUE(entry, const struct hlsl_ir_function,entry);
return strcmp(name, func->name);
}
static const struct wine_rb_functions function_rb_funcs =
{
d3dcompiler_alloc_rb,
d3dcompiler_realloc_rb,
d3dcompiler_free_rb,
compare_function_rb,
};
void init_functions_tree(struct wine_rb_tree *funcs)
{
if (wine_rb_init(&hlsl_ctx.functions, &function_rb_funcs) == -1)
ERR("Failed to initialize functions rbtree.\n");
}
static const char *debug_base_type(const struct hlsl_type *type) static const char *debug_base_type(const struct hlsl_type *type)
{ {
const char *name = "(unknown)"; const char *name = "(unknown)";
@ -2198,11 +2296,11 @@ static void debug_dump_instr(const struct hlsl_ir_node *instr)
} }
} }
void debug_dump_ir_function(const struct hlsl_ir_function_decl *func) void debug_dump_ir_function_decl(const struct hlsl_ir_function_decl *func)
{ {
struct hlsl_ir_var *param; struct hlsl_ir_var *param;
TRACE("Dumping function %s.\n", debugstr_a(func->name)); TRACE("Dumping function %s.\n", debugstr_a(func->func->name));
TRACE("Function parameters:\n"); TRACE("Function parameters:\n");
LIST_FOR_EACH_ENTRY(param, func->parameters, struct hlsl_ir_var, node.entry) LIST_FOR_EACH_ENTRY(param, func->parameters, struct hlsl_ir_var, node.entry)
{ {
@ -2370,11 +2468,69 @@ void free_instr(struct hlsl_ir_node *node)
} }
} }
void free_function(struct hlsl_ir_function_decl *func) void free_function_decl(struct hlsl_ir_function_decl *func)
{ {
d3dcompiler_free((void *)func->name);
d3dcompiler_free((void *)func->semantic); d3dcompiler_free((void *)func->semantic);
d3dcompiler_free(func->parameters); d3dcompiler_free(func->parameters);
free_instr_list(func->body); free_instr_list(func->body);
d3dcompiler_free(func); d3dcompiler_free(func);
} }
static void free_function_decl_rb(struct wine_rb_entry *entry, void *context)
{
free_function_decl(WINE_RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry));
}
void free_function(struct hlsl_ir_function *func)
{
wine_rb_destroy(&func->overloads, free_function_decl_rb, NULL);
d3dcompiler_free((void *)func->name);
}
void free_function_rb(struct wine_rb_entry *entry, void *context)
{
free_function(WINE_RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry));
}
void add_function_decl(struct wine_rb_tree *funcs, char *name, struct hlsl_ir_function_decl *decl, BOOL intrinsic)
{
struct hlsl_ir_function *func;
struct wine_rb_entry *func_entry, *old_entry;
func_entry = wine_rb_get(funcs, name);
if (func_entry)
{
func = WINE_RB_ENTRY_VALUE(func_entry, struct hlsl_ir_function, entry);
decl->func = func;
if ((old_entry = wine_rb_get(&func->overloads, decl->parameters)))
{
struct hlsl_ir_function_decl *old_decl =
WINE_RB_ENTRY_VALUE(old_entry, struct hlsl_ir_function_decl, entry);
if (!decl->body)
{
free_function_decl(decl);
d3dcompiler_free(name);
return;
}
wine_rb_remove(&func->overloads, decl->parameters);
free_function_decl(old_decl);
}
wine_rb_put(&func->overloads, decl->parameters, &decl->entry);
d3dcompiler_free(name);
return;
}
func = d3dcompiler_alloc(sizeof(*func));
func->name = name;
if (wine_rb_init(&func->overloads, &hlsl_ir_function_decl_rb_funcs) == -1)
{
ERR("Failed to initialize function rbtree.\n");
d3dcompiler_free(name);
d3dcompiler_free(func);
return;
}
decl->func = func;
wine_rb_put(&func->overloads, decl->parameters, &decl->entry);
func->intrinsic = intrinsic;
wine_rb_put(funcs, func->name, &func->entry);
}