Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
---
A new var_def is now initialized to the content of the same var_def
in earlier stack frames.
I still believe this is more complicated than it should be (i.e., harder
to check and therefore more prone to bugs), but maybe it's correct anyway.
---
libs/vkd3d-shader/hlsl_codegen.c | 148 +++++++++++++++++++++++++++----
1 file changed, 133 insertions(+), 15 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index 75716bdf..d09a6a3b 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -290,6 +290,7 @@ struct copy_propagation_var_def
struct copy_propagation_state
{
struct rb_tree var_defs;
+ struct copy_propagation_state *parent;
};
static int copy_propagation_var_def_compare(const void *key, const struct rb_entry *entry)
@@ -308,9 +309,12 @@ static void copy_propagation_var_def_destroy(struct rb_entry *entry, void *conte
}
static struct copy_propagation_var_def *copy_propagation_get_var_def(struct copy_propagation_state *state,
- struct hlsl_ir_var *var)
+ const struct hlsl_ir_var *var)
{
- struct rb_entry *entry = rb_get(&state->var_defs, var);
+ struct rb_entry *entry;
+
+ while (state && !(entry = rb_get(&state->var_defs, var)))
+ state = state->parent;
if (entry)
return RB_ENTRY_VALUE(entry, struct copy_propagation_var_def, entry);
@@ -321,8 +325,8 @@ static struct copy_propagation_var_def *copy_propagation_get_var_def(struct copy
static struct copy_propagation_var_def *copy_propagation_create_var_def(struct hlsl_ctx *ctx,
struct copy_propagation_state *state, struct hlsl_ir_var *var)
{
+ struct copy_propagation_var_def *var_def, *prev_var_def;
struct rb_entry *entry = rb_get(&state->var_defs, var);
- struct copy_propagation_var_def *var_def;
int res;
if (entry)
@@ -331,6 +335,10 @@ static struct copy_propagation_var_def *copy_propagation_create_var_def(struct h
if (!(var_def = hlsl_alloc(ctx, offsetof(struct copy_propagation_var_def, values[var->data_type->reg_size]))))
return NULL;
+ prev_var_def = copy_propagation_get_var_def(state, var);
+ if (prev_var_def)
+ memcpy(var_def->values, prev_var_def->values, var->data_type->reg_size * sizeof(*var_def->values));
+
var_def->var = var;
res = rb_put(&state->var_defs, var, &var_def->entry);
@@ -339,12 +347,6 @@ static struct copy_propagation_var_def *copy_propagation_create_var_def(struct h
return var_def;
}
-static void copy_propagation_invalidate_whole_variable(struct copy_propagation_var_def *var_def)
-{
- TRACE("Invalidate variable %s.\n", var_def->var->name);
- memset(var_def->values, 0, sizeof(*var_def->values) * var_def->var->data_type->reg_size);
-}
-
static void copy_propagation_set_value(struct copy_propagation_var_def *var_def, unsigned int offset,
unsigned char writemask, struct hlsl_ir_node *node)
{
@@ -354,7 +356,7 @@ static void copy_propagation_set_value(struct copy_propagation_var_def *var_def,
{
if (writemask & (1u << i))
{
- TRACE("Variable %s[%u] is written by instruction %p%s.\n",
+ TRACE("Variable %s[%u] updated with value from %p%s.\n",
var_def->var->name, offset + i, node, debug_hlsl_writemask(1u << i));
var_def->values[offset + i].node = node;
var_def->values[offset + i].component = j++;
@@ -362,6 +364,99 @@ static void copy_propagation_set_value(struct copy_propagation_var_def *var_def,
}
}
+static void copy_propagation_invalidate_whole_variable(struct copy_propagation_state *state,
+ struct copy_propagation_var_def *var_def)
+{
+ const struct hlsl_ir_var *var = var_def->var;
+
+ TRACE("Invalidate variable %s.\n", var->name);
+ while (state)
+ {
+ if ((var_def = copy_propagation_get_var_def(state, var)))
+ memset(var_def->values, 0, sizeof(*var_def->values) * var_def->var->data_type->reg_size);
+ state = state->parent;
+ }
+}
+
+static void copy_propagation_invalidate_variable_partial(struct copy_propagation_state *state,
+ struct copy_propagation_var_def *var_def, unsigned int offset, unsigned char writemask)
+{
+ const struct hlsl_ir_var *var = var_def->var;
+
+ TRACE("Invalidate variable %s[%u]%s.\n", var->name, offset, debug_hlsl_writemask(writemask));
+ while (state)
+ {
+ if ((var_def = copy_propagation_get_var_def(state, var)))
+ copy_propagation_set_value(var_def, offset, writemask, NULL);
+ state = state->parent;
+ }
+}
+
+static void copy_propagation_invalidate_from_block(struct hlsl_ctx *ctx, struct copy_propagation_state *state,
+ struct hlsl_block *block)
+{
+ struct hlsl_ir_node *instr;
+
+ LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry)
+ {
+ switch (instr->type)
+ {
+ case HLSL_IR_STORE:
+ {
+ struct hlsl_ir_store *store = hlsl_ir_store(instr);
+ struct copy_propagation_var_def *var_def;
+ struct hlsl_deref *lhs = &store->lhs;
+ struct hlsl_ir_var *var = lhs->var;
+ unsigned int offset;
+
+ if (!(var_def = copy_propagation_get_var_def(state, var)))
+ continue;
+
+ if (hlsl_offset_from_deref(lhs, &offset))
+ copy_propagation_invalidate_variable_partial(state, var_def, offset, store->writemask);
+ else
+ copy_propagation_invalidate_whole_variable(state, var_def);
+
+ break;
+ }
+
+ case HLSL_IR_IF:
+ {
+ struct hlsl_ir_if *iff = hlsl_ir_if(instr);
+
+ copy_propagation_invalidate_from_block(ctx, state, &iff->then_instrs);
+ copy_propagation_invalidate_from_block(ctx, state, &iff->else_instrs);
+
+ break;
+ }
+
+ case HLSL_IR_LOOP:
+ {
+ struct hlsl_ir_loop *loop = hlsl_ir_loop(instr);
+
+ copy_propagation_invalidate_from_block(ctx, state, &loop->body);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+
+static void copy_propagation_state_destroy(struct copy_propagation_state *state)
+{
+ rb_destroy(&state->var_defs, copy_propagation_var_def_destroy, NULL);
+}
+
+static void copy_propagation_state_init(struct hlsl_ctx *ctx, struct copy_propagation_state *state,
+ struct copy_propagation_state *parent)
+{
+ rb_init(&state->var_defs, copy_propagation_var_def_compare);
+ state->parent = parent;
+}
+
static struct hlsl_ir_node *copy_propagation_compute_replacement(struct copy_propagation_var_def *var_def,
unsigned int offset, unsigned int count, unsigned int *swizzle)
{
@@ -433,7 +528,30 @@ static void copy_propagation_record_store(struct hlsl_ctx *ctx, struct hlsl_ir_s
if (hlsl_offset_from_deref(lhs, &offset))
copy_propagation_set_value(var_def, offset, store->writemask, store->rhs.node);
else
- copy_propagation_invalidate_whole_variable(var_def);
+ copy_propagation_invalidate_whole_variable(state, var_def);
+}
+
+static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_block *block,
+ struct copy_propagation_state *state);
+
+static bool copy_propagation_process_if(struct hlsl_ctx *ctx, struct hlsl_ir_if *iff,
+ struct copy_propagation_state *state)
+{
+ struct copy_propagation_state inner_state;
+ bool progress = false;
+
+ copy_propagation_state_init(ctx, &inner_state, state);
+ progress |= copy_propagation_transform_block(ctx, &iff->then_instrs, &inner_state);
+ copy_propagation_state_destroy(&inner_state);
+
+ copy_propagation_state_init(ctx, &inner_state, state);
+ progress |= copy_propagation_transform_block(ctx, &iff->else_instrs, &inner_state);
+ copy_propagation_state_destroy(&inner_state);
+
+ copy_propagation_invalidate_from_block(ctx, state, &iff->then_instrs);
+ copy_propagation_invalidate_from_block(ctx, state, &iff->else_instrs);
+
+ return progress;
}
static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_block *block,
@@ -455,8 +573,8 @@ static bool copy_propagation_transform_block(struct hlsl_ctx *ctx, struct hlsl_b
break;
case HLSL_IR_IF:
- FIXME("Copy propagation doesn't support conditionals yet, leaving.\n");
- return progress;
+ progress |= copy_propagation_process_if(ctx, hlsl_ir_if(instr), state);
+ break;
case HLSL_IR_LOOP:
FIXME("Copy propagation doesn't support loops yet, leaving.\n");
@@ -475,11 +593,11 @@ static bool copy_propagation_execute(struct hlsl_ctx *ctx, struct hlsl_block *bl
struct copy_propagation_state state;
bool progress;
- rb_init(&state.var_defs, copy_propagation_var_def_compare);
+ copy_propagation_state_init(ctx, &state, NULL);
progress = copy_propagation_transform_block(ctx, block, &state);
- rb_destroy(&state.var_defs, copy_propagation_var_def_destroy, NULL);
+ copy_propagation_state_destroy(&state);
return progress;
}
--
2.34.1