From: Francisco Casas fcasas@codeweavers.com
copy_propagation_transform_object_load() currently retrieves true, which indicates that there was progress, even if the input dereference remains the same.
This can happen repeatedly if an uninitialized object is copied onto itself, as in the tests added in this patch. This results on the compilation getting stuck on an endless loop.
This patch checks if the deref didn't change, to retrieve false in that case. --- libs/vkd3d-shader/hlsl.c | 27 +++++++++++++++++++++ libs/vkd3d-shader/hlsl.h | 2 ++ libs/vkd3d-shader/hlsl_codegen.c | 3 +++ tests/object-references.shader_test | 37 +++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 8aa289ac..627381bb 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -846,6 +846,33 @@ void hlsl_cleanup_deref(struct hlsl_deref *deref) hlsl_src_remove(&deref->offset); }
+bool hlsl_derefs_are_equal(struct hlsl_ctx *ctx, const struct hlsl_deref *deref1, + const struct hlsl_deref *deref2) +{ + unsigned int i; + + assert(!deref1->offset.node); + assert(!deref2->offset.node); + + if (deref1->var != deref2->var) + return false; + if (deref1->path_len != deref2->path_len) + return false; + + for (i = 0; i < deref1->path_len; ++i) + { + const struct hlsl_ir_node *node1 = deref1->path[i].node, *node2 = deref2->path[i].node; + + if (node1 == node2) + continue; + if (node1->type != HLSL_IR_CONSTANT || node2->type != HLSL_IR_CONSTANT) + return false; + if (hlsl_ir_constant(node1)->value[0].u != hlsl_ir_constant(node2)->value[0].u) + return false; + } + return true; +} + /* Initializes a simple variable derefence, so that it can be passed to load/store functions. */ void hlsl_init_simple_deref_from_var(struct hlsl_deref *deref, struct hlsl_ir_var *var) { diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index b6a593ca..3d3825c2 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -752,6 +752,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other); void hlsl_cleanup_deref(struct hlsl_deref *deref); +bool hlsl_derefs_are_equal(struct hlsl_ctx *ctx, const struct hlsl_deref *deref1, + const struct hlsl_deref *deref2);
void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new);
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 6e4168fc..bd5a2c5a 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -773,6 +773,9 @@ static bool copy_propagation_transform_object_load(struct hlsl_ctx *ctx, /* Only HLSL_IR_LOAD can produce an object. */ load = hlsl_ir_load(instr);
+ if (hlsl_derefs_are_equal(ctx, deref, &load->src)) + return false; + hlsl_cleanup_deref(deref); hlsl_copy_deref(ctx, deref, &load->src);
diff --git a/tests/object-references.shader_test b/tests/object-references.shader_test index 12f745e6..c4b04620 100644 --- a/tests/object-references.shader_test +++ b/tests/object-references.shader_test @@ -1,3 +1,15 @@ +[pixel shader fail todo] +sampler sam; + +float4 main() : sv_target +{ + Texture2D tex; + + tex = tex; // Uninitialized assignment to self. + return tex.Sample(sam, float2(0, 0)); +} + + [require] shader model >= 4.0
@@ -155,3 +167,28 @@ float4 main() : sv_target uniform 0 float 10.0 todo draw quad todo probe (0, 0) rgba (11.0, 12.0, 13.0, 11.0) + + +[require] +shader model >= 5.0 + + +[texture 0] +size (1, 1) +1.0 2.0 3.0 4.0 + +[pixel shader] +struct apple { + Texture2D tex; + float4 fo : COLOR; +}; + +float4 main(struct apple input) : sv_target +{ + input.tex = input.tex; // Assignment to self. + return input.tex.Load(int3(0, 0, 0)); +} + +[test] +draw quad +probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)