From: Francisco Casas fcasas@codeweavers.com
By replacing the value pointer of the last index in the chain with a load to a synthetic variable that holds the value.
This also allows to index nodes that are not hlsl_ir_loads such as:
(a + b)[1] --- libs/vkd3d-shader/hlsl.c | 4 +-- libs/vkd3d-shader/hlsl_codegen.c | 46 +++++++++++++++++++++++++++++--- tests/expr-indexing.shader_test | 12 ++++----- tests/side-effects.shader_test | 2 +- 4 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 56dea24f..16cd35ee 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -463,9 +463,7 @@ bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *d
if (ptr->type != HLSL_IR_LOAD) { - /* This should be an hlsl_error() for invalid l-values, but indexing non-load expressions is - * also not supported yet so we use a hlsl_fixme() for now. */ - hlsl_fixme(ctx, &chain->loc, "Indexing %s.", hlsl_node_type_to_string(ptr->type)); + hlsl_error(ctx, &chain->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_LVALUE, "Invalid l-value."); return false; } load = hlsl_ir_load(ptr); diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index b743be69..4b13a77c 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -731,6 +731,45 @@ static bool lower_calls(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void * return true; }
+/* This pass replaces the values that each index chain points to with a load to a copy in a + * synthetic variable. So that later, hlsl_derefs can be safely created from these loads. */ +static bool copy_index_values(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_index *index; + struct hlsl_ir_node *val; + + if (instr->type != HLSL_IR_INDEX) + return false; + + index = hlsl_ir_index(instr); + val = index->val.node; + + if (val->type != HLSL_IR_INDEX) + { + struct hlsl_ir_store *store; + struct hlsl_ir_load *load; + struct hlsl_ir_var *var; + + if (!(var = hlsl_new_synthetic_var(ctx, "index-val", val->data_type, &val->loc))) + return false; + + if (!(store = hlsl_new_simple_store(ctx, var, val))) + return false; + list_add_before(&instr->entry, &store->node.entry); + + if (!(load = hlsl_new_var_load(ctx, var, instr->loc))) + return false; + list_add_before(&instr->entry, &load->node.entry); + + hlsl_src_remove(&index->val); + hlsl_src_from_node(&index->val, &load->node); + + return true; + } + + return false; +} + /* Single hlsl_ir_index instructions on column-major matrices cannot be turned into derefs, however, * index chains that refer to a single component can be. This pass turns the former in the latter. */ static bool lower_noncontiguous_matrix_index_loads(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) @@ -796,9 +835,9 @@ static bool lower_noncontiguous_matrix_index_loads(struct hlsl_ctx *ctx, struct * For the latter case, this pass takes care of lowering hlsl_ir_indexes (and index chains) into * individual hlsl_ir_loads. * It is worth noting that the generated hlsl_ir_loads don't load from a copy of the variable loaded - * at the beginning of the index chain, but from the same variable instead, because it is assumed - * that the value of the variable won't change between the the hlsl_ir_load instruction and the - * hlsl_ir_index. */ + * at the beginning of the index chain, but from the same variable instead. This can be done because + * the copy_index_values pass takes care of creating the copies and pointing the index chains to + * them. */ static bool lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { struct hlsl_ir_index *index; @@ -3328,6 +3367,7 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
while (transform_ir(ctx, lower_calls, body, NULL));
+ transform_ir(ctx, copy_index_values, body, NULL); transform_ir(ctx, lower_noncontiguous_matrix_index_loads, body, NULL); transform_ir(ctx, lower_index_loads, body, NULL);
diff --git a/tests/expr-indexing.shader_test b/tests/expr-indexing.shader_test index 5ced28c5..546deac7 100644 --- a/tests/expr-indexing.shader_test +++ b/tests/expr-indexing.shader_test @@ -1,4 +1,4 @@ -[pixel shader todo] +[pixel shader] float4 a, b;
float4 main() : sv_target @@ -9,8 +9,8 @@ float4 main() : sv_target [test] uniform 0 float4 1.0 2.0 3.0 4.0 uniform 4 float4 5.0 6.0 7.0 8.0 -todo draw quad -todo probe all rgba (8.0, 8.0, 8.0, 8.0) +draw quad +probe all rgba (8.0, 8.0, 8.0, 8.0)
[pixel shader todo] @@ -30,7 +30,7 @@ todo draw quad todo probe all rgba (10.0, 10.0, 10.0, 10.0)
-[pixel shader todo] +[pixel shader] float4 a; int i;
@@ -41,8 +41,8 @@ float4 main() : sv_target
[test] uniform 0 float4 1.0 2.0 3.0 4.0 -todo draw quad -todo probe all rgba (3.0, 3.0, 3.0, 3.0) +draw quad +probe all rgba (3.0, 3.0, 3.0, 3.0)
[pixel shader todo] diff --git a/tests/side-effects.shader_test b/tests/side-effects.shader_test index 224b4c21..c961ed12 100644 --- a/tests/side-effects.shader_test +++ b/tests/side-effects.shader_test @@ -24,4 +24,4 @@ float4 main() : sv_target
[test] draw quad -todo probe all rgba (11.0, 11.0, 11.0, 11.0) +probe all rgba (11.0, 11.0, 11.0, 11.0)