Summary: | Adding a redundant single-iteration do-while loop causes different image to be rendered | ||
---|---|---|---|
Product: | Mesa | Reporter: | Abel Briggs <abelbriggs1> |
Component: | glsl-compiler | Assignee: | Ian Romanick <idr> |
Status: | RESOLVED FIXED | QA Contact: | Intel 3D Bugs Mailing List <intel-3d-bugs> |
Severity: | normal | ||
Priority: | medium | ||
Version: | git | ||
Hardware: | x86-64 (AMD64) | ||
OS: | Linux (All) | ||
Whiteboard: | |||
i915 platform: | i915 features: | ||
Attachments: | piglit shader tests, images, diff |
Description
Abel Briggs
2019-06-20 17:18:42 UTC
I'm not able to reproduce this bug on i965. It looks like llvmpipe (from Fedora 30, Mesa 19.0.5) produces the variant.png image. The other bug was in a GLSL IR pass that i965 doesn't use, so this one probably is too. I'll take a look. The difference in the output of "./glsl_compiler --version 300 --dump-lir" for both shaders is below. It looks like the loop in the second shader is (incorrectly) unrolled twice. --- /tmp/before.txt 2019-06-20 12:48:58.425392405 -0700 +++ /tmp/after.txt 2019-06-20 12:49:05.983437986 -0700 @@ -72,6 +72,14 @@ ) ()) + (if (var_ref checkSwap_retval) ( + (declare (temporary ) float assignment_tmp@2) + (assign (x) (var_ref assignment_tmp@2) (array_ref (var_ref data) (var_ref i) ) ) + (assign (x) (array_ref (var_ref data) (var_ref i) ) (array_ref (var_ref data) (var_ref j) ) ) + (assign (x) (array_ref (var_ref data) (var_ref j) ) (var_ref assignment_tmp@2) ) + ) + ()) + (assign (x) (var_ref j) (expression int + (var_ref j) (constant int (1)) ) ) )) @@ -87,12 +95,12 @@ (assign (xyzw) (var_ref _GLF_color) (var_ref vec_ctor) ) ) ( - (declare (temporary ) vec4 vec_ctor@2) - (assign (w) (var_ref vec_ctor@2) (constant float (1.000000)) ) - (assign (x) (var_ref vec_ctor@2) (expression float / (array_ref (var_ref data) (constant int (5)) ) (constant float (10.000000)) ) ) - (assign (y) (var_ref vec_ctor@2) (expression float / (array_ref (var_ref data) (constant int (9)) ) (constant float (10.000000)) ) ) - (assign (z) (var_ref vec_ctor@2) (expression float / (array_ref (var_ref data) (constant int (0)) ) (constant float (10.000000)) ) ) - (assign (xyzw) (var_ref _GLF_color) (var_ref vec_ctor@2) ) + (declare (temporary ) vec4 vec_ctor@3) + (assign (w) (var_ref vec_ctor@3) (constant float (1.000000)) ) + (assign (x) (var_ref vec_ctor@3) (expression float / (array_ref (var_ref data) (constant int (5)) ) (constant float (10.000000)) ) ) + (assign (y) (var_ref vec_ctor@3) (expression float / (array_ref (var_ref data) (constant int (9)) ) (constant float (10.000000)) ) ) + (assign (z) (var_ref vec_ctor@3) (expression float / (array_ref (var_ref data) (constant int (0)) ) (constant float (10.000000)) ) ) + (assign (xyzw) (var_ref _GLF_color) (var_ref vec_ctor@3) ) )) )) Setting debug = true in do_common_optimization (src/compiler/glsl/glsl_parser_extras.cpp), it seems the bad code appears in do_dead_code_unlinked. (In reply to Ian Romanick from comment #3) > Setting debug = true in do_common_optimization > (src/compiler/glsl/glsl_parser_extras.cpp), it seems the bad code appears in > do_dead_code_unlinked. Scratch that. It is unroll_loops, but unroll_loops doesn't log its progress the way the other optimization passes do. The problem is this bit of code loop_unroll_visitor::simple_unroll. if (limit_if != first_ir->as_if() || exit_branch_has_instructions) iterations++; The check that the first thing in the loop is an if-statement expects that to only occur when the if-statement is a terminator for the loop (e.g., if (i > 6) break;). This loop starts with an if-statement that is not a terminator, so the loop iteration count is incorrectly incremented. This MR should fix the bug: https://gitlab.freedesktop.org/mesa/mesa/merge_requests/1152 And this MR has a minimal test case: https://gitlab.freedesktop.org/mesa/piglit/merge_requests/88 I'm running both through Intel's CI on G33 hardware. That very, very old hardware has OpenGL ES 2.0, but it does not use the NIR loop unrolling path. It should hit this bug... I'll find out for sure in the morning. I tried the test and the fix on my local machine using softpipe. @abel: Can you test the fix on nouveau? (In reply to Ian Romanick from comment #6) > This MR should fix the bug: > > https://gitlab.freedesktop.org/mesa/mesa/merge_requests/1152 > > And this MR has a minimal test case: > > https://gitlab.freedesktop.org/mesa/piglit/merge_requests/88 > > I'm running both through Intel's CI on G33 hardware. That very, very old > hardware has OpenGL ES 2.0, but it does not use the NIR loop unrolling path. > It should hit this bug... I'll find out for sure in the morning. I tried > the test and the fix on my local machine using softpipe. > > @abel: Can you test the fix on nouveau? I pulled your repo and ran the shader, and I can confirm that the issue is fixed (the reference and variant now render the same image). Fixed by: commit ee1c69faddb3624ace6548dafaff50549a031380 Author: Ian Romanick <ian.d.romanick@intel.com> Date: Thu Jun 20 15:48:48 2019 -0700 glsl: Don't increase the iteration count when there are no terminators Incrementing the iteration count was intended to fix an off-by-one error when the first terminator was superseded by a later terminator. If there is no first terminator or later terminator, there is no off-by-one error. Incrementing the loop count creates one. This can be seen in loops like: do { if (something) { // No breaks or continues here. } } while (false); Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com> Tested-by: Abel Briggs <abelbriggs1@hotmail.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=110953 Fixes: 646621c66da ("glsl: make loop unrolling more like the nir unrolling path") |
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.