1 /*
2 * Copyright © 2024 Valve Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "nir_test.h"
25
26 class nir_opt_loop_test : public nir_test {
27 protected:
28 nir_opt_loop_test();
29
30 nir_deref_instr *add_loop_terminators(nir_if **term1, nir_if **term2,
31 bool break_in_else, bool deref_array);
32 void create_loop_phis(nir_loop *loop, nir_if *term1, nir_if *term2,
33 nir_def *def1, nir_def *def2);
34 void test_merged_if(bool break_in_else);
35
36 nir_def *in_def;
37 nir_variable *out_var;
38 nir_variable *ubo_var;
39 nir_variable *ubo_var_array;
40 };
41
nir_opt_loop_test()42 nir_opt_loop_test::nir_opt_loop_test()
43 : nir_test::nir_test("nir_opt_loop_test", MESA_SHADER_FRAGMENT)
44 {
45 nir_variable *var = nir_variable_create(b->shader, nir_var_shader_in, glsl_int_type(), "in");
46 in_def = nir_load_var(b, var);
47
48 ubo_var = nir_variable_create(b->shader, nir_var_mem_ubo, glsl_int_type(), "ubo1");
49 ubo_var_array = nir_variable_create(b->shader, nir_var_mem_ubo, glsl_array_type(glsl_int_type(), 4, 0), "ubo_array");
50
51 out_var = nir_variable_create(b->shader, nir_var_shader_out, glsl_int_type(), "out");
52 }
53
54 nir_deref_instr *
add_loop_terminators(nir_if ** term1,nir_if ** term2,bool break_in_else,bool deref_array)55 nir_opt_loop_test::add_loop_terminators(nir_if **term1, nir_if **term2,
56 bool break_in_else, bool deref_array)
57 {
58 /* Add first terminator */
59 nir_def *one = nir_imm_int(b, 1);
60 nir_def *cmp_result = nir_ieq(b, in_def, one);
61 nir_if *nif = nir_push_if(b, cmp_result);
62
63 if (break_in_else)
64 nir_push_else(b, nif);
65
66 nir_jump(b, nir_jump_break);
67 nir_pop_if(b, nif);
68
69 if (term1)
70 *term1 = nif;
71
72 nir_deref_instr *deref;
73 if (deref_array) {
74 nir_def *index = nir_imm_int(b, 3);
75 deref = nir_build_deref_array(b, nir_build_deref_var(b, ubo_var_array), index);
76 } else {
77 deref = nir_build_deref_var(b, ubo_var);
78 }
79 nir_def *ubo_def = nir_load_deref(b, deref);
80
81 /* Add second terminator */
82 nir_def *two = nir_imm_int(b, 2);
83 nir_def *cmp_result2 = nir_ieq(b, ubo_def, two);
84 nir_if *nif2 = nir_push_if(b, cmp_result2);
85
86 if (break_in_else)
87 nir_push_else(b, nif2);
88
89 nir_jump(b, nir_jump_break);
90 nir_pop_if(b, nif2);
91
92 if (term2)
93 *term2 = nif2;
94
95 return deref;
96 }
97
98 void
create_loop_phis(nir_loop * loop,nir_if * term1,nir_if * term2,nir_def * def1,nir_def * def2)99 nir_opt_loop_test::create_loop_phis(nir_loop *loop,
100 nir_if *term1, nir_if *term2,
101 nir_def *def1, nir_def *def2)
102 {
103 nir_phi_instr *phi_instr = nir_phi_instr_create(b->shader);
104 nir_def_init(&phi_instr->instr, &phi_instr->def, 1, 32);
105 nir_phi_instr_add_src(phi_instr, nir_if_first_then_block(term1), def1);
106 nir_phi_instr_add_src(phi_instr, nir_if_first_then_block(term2), def2);
107
108 nir_instr_insert(nir_after_cf_node(&loop->cf_node),
109 &phi_instr->instr);
110 }
111
112 void
test_merged_if(bool break_in_else)113 nir_opt_loop_test::test_merged_if(bool break_in_else)
114 {
115 /* Tests that opt_loop_merge_terminators results in valid nir and that
116 * the test condition is correct based on the location of the break in
117 * the terminators.
118 */
119 nir_loop *loop = nir_push_loop(b);
120
121 nir_if *term1;
122 nir_if *term2;
123 add_loop_terminators(&term1, &term2, break_in_else, false);
124
125 nir_pop_loop(b, loop);
126
127 ASSERT_TRUE(nir_opt_loop(b->shader));
128
129 nir_validate_shader(b->shader, NULL);
130 }
131
TEST_F(nir_opt_loop_test,opt_loop_merge_terminators_break_in_then)132 TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_break_in_then)
133 {
134 test_merged_if(false);
135
136 check_nir_string(NIR_REFERENCE_SHADER(R"(
137 shader: MESA_SHADER_FRAGMENT
138 name: nir_opt_loop_test
139 subgroup_size: 0
140 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
141 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
142 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
143 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
144 decl_function main () (entrypoint)
145
146 impl main {
147 block b0: // preds:
148 32 %0 = deref_var &in (shader_in int)
149 32 %1 = @load_deref (%0) (access=none)
150 // succs: b1
151 loop {
152 block b1: // preds: b0 b7
153 32 %2 = load_const (0x00000001)
154 1 %3 = ieq %1, %2 (0x1)
155 // succs: b2 b3
156 if %3 {
157 block b2: // preds: b1
158 1 %4 = undefined
159 // succs: b4
160 } else {
161 block b3: // preds: b1
162 32 %5 = deref_var &ubo1 (ubo int)
163 32 %6 = @load_deref (%5) (access=none)
164 32 %7 = load_const (0x00000002)
165 1 %8 = ieq %6, %7 (0x2)
166 // succs: b4
167 }
168 block b4: // preds: b2 b3
169 1 %9 = phi b3: %8, b2: %4
170 1 %10 = ior %9, %3
171 // succs: b5 b6
172 if %10 {
173 block b5:// preds: b4
174 break
175 // succs: b8
176 } else {
177 block b6: // preds: b4, succs: b7
178 }
179 block b7: // preds: b6, succs: b1
180 }
181 block b8: // preds: b5, succs: b9
182 block b9:
183 }
184 )"));
185 }
186
TEST_F(nir_opt_loop_test,opt_loop_merge_terminators_break_in_else)187 TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_break_in_else)
188 {
189 test_merged_if(true);
190
191 check_nir_string(NIR_REFERENCE_SHADER(R"(
192 shader: MESA_SHADER_FRAGMENT
193 name: nir_opt_loop_test
194 subgroup_size: 0
195 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
196 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
197 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
198 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
199 decl_function main () (entrypoint)
200
201 impl main {
202 block b0: // preds:
203 32 %0 = deref_var &in (shader_in int)
204 32 %1 = @load_deref (%0) (access=none)
205 // succs: b1
206 loop {
207 block b1: // preds: b0 b7
208 32 %2 = load_const (0x00000001)
209 1 %3 = ieq %1, %2 (0x1)
210 // succs: b2 b3
211 if %3 {
212 block b2: // preds: b1
213 32 %4 = deref_var &ubo1 (ubo int)
214 32 %5 = @load_deref (%4) (access=none)
215 32 %6 = load_const (0x00000002)
216 1 %7 = ieq %5, %6 (0x2)
217 // succs: b4
218 } else {
219 block b3: // preds: b1
220 1 %8 = undefined
221 // succs: b4
222 }
223 block b4: // preds: b2 b3
224 1 %9 = phi b2: %7, b3: %8
225 1 %10 = iand %9, %3
226 // succs: b5 b6
227 if %10 {
228 block b5: // preds: b4, succs: b7
229 } else {
230 block b6:// preds: b4
231 break
232 // succs: b8
233 }
234 block b7: // preds: b5, succs: b1
235 }
236 block b8: // preds: b6, succs: b9
237 block b9:
238 }
239 )"));
240 }
241
TEST_F(nir_opt_loop_test,opt_loop_merge_terminators_deref_after_first_if)242 TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_deref_after_first_if)
243 {
244 /* Tests that opt_loop_merge_terminators creates valid nir after it merges
245 * terminators that have a deref statement between them:
246 */
247 nir_loop *loop = nir_push_loop(b);
248
249 nir_deref_instr *deref = add_loop_terminators(NULL, NULL, false, false);
250
251 /* Load from deref that will be moved inside the continue branch of the
252 * first if-statements continue block. If not handled correctly during
253 * the merge this will fail nir validation.
254 */
255 nir_def *ubo_def = nir_load_deref(b, deref);
256 nir_store_var(b, out_var, ubo_def, 1);
257
258 nir_pop_loop(b, loop);
259
260 ASSERT_TRUE(nir_opt_loop(b->shader));
261
262 nir_validate_shader(b->shader, NULL);
263
264 check_nir_string(NIR_REFERENCE_SHADER(R"(
265 shader: MESA_SHADER_FRAGMENT
266 name: nir_opt_loop_test
267 subgroup_size: 0
268 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
269 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
270 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
271 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
272 decl_function main () (entrypoint)
273
274 impl main {
275 block b0: // preds:
276 32 %0 = deref_var &in (shader_in int)
277 32 %1 = @load_deref (%0) (access=none)
278 // succs: b1
279 loop {
280 block b1: // preds: b0 b7
281 32 %2 = load_const (0x00000001)
282 1 %3 = ieq %1, %2 (0x1)
283 // succs: b2 b3
284 if %3 {
285 block b2: // preds: b1
286 1 %4 = undefined
287 // succs: b4
288 } else {
289 block b3: // preds: b1
290 32 %5 = deref_var &ubo1 (ubo int)
291 32 %6 = @load_deref (%5) (access=none)
292 32 %7 = load_const (0x00000002)
293 1 %8 = ieq %6, %7 (0x2)
294 // succs: b4
295 }
296 block b4: // preds: b2 b3
297 1 %9 = phi b3: %8, b2: %4
298 1 %10 = ior %9, %3
299 // succs: b5 b6
300 if %10 {
301 block b5:// preds: b4
302 break
303 // succs: b8
304 } else {
305 block b6: // preds: b4, succs: b7
306 }
307 block b7: // preds: b6
308 32 %11 = deref_var &ubo1 (ubo int)
309 32 %12 = @load_deref (%11) (access=none)
310 32 %13 = deref_var &out (shader_out int)
311 @store_deref (%13, %12) (wrmask=x, access=none)
312 // succs: b1
313 }
314 block b8: // preds: b5, succs: b9
315 block b9:
316 }
317 )"));
318 }
319
TEST_F(nir_opt_loop_test,opt_loop_merge_terminators_deref_phi_index)320 TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_deref_phi_index)
321 {
322 /* Tests that opt_loop_merge_terminators creates valid nir after it merges
323 * terminators that have a deref statement and index value between them and
324 * where that deref and index are both later used again later in the code:
325 */
326 nir_loop *loop = nir_push_loop(b);
327
328 nir_deref_instr *deref = add_loop_terminators(NULL, NULL, false, true);
329
330 /* Load from deref that will be moved inside the continue branch of the
331 * first if-statements continue block. If not handled correctly during
332 * the merge this will fail nir validation.
333 */
334 nir_def *ubo_def = nir_load_deref(b, deref);
335 nir_store_var(b, out_var, ubo_def, 1);
336
337 nir_pop_loop(b, loop);
338
339 ASSERT_TRUE(nir_opt_loop(b->shader));
340
341 nir_validate_shader(b->shader, NULL);
342
343 check_nir_string(NIR_REFERENCE_SHADER(R"(
344 shader: MESA_SHADER_FRAGMENT
345 name: nir_opt_loop_test
346 subgroup_size: 0
347 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
348 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
349 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
350 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
351 decl_function main () (entrypoint)
352
353 impl main {
354 block b0: // preds:
355 32 %0 = deref_var &in (shader_in int)
356 32 %1 = @load_deref (%0) (access=none)
357 // succs: b1
358 loop {
359 block b1: // preds: b0 b7
360 32 %2 = load_const (0x00000001)
361 1 %3 = ieq %1, %2 (0x1)
362 // succs: b2 b3
363 if %3 {
364 block b2: // preds: b1
365 1 %4 = undefined
366 32 %5 = undefined
367 // succs: b4
368 } else {
369 block b3: // preds: b1
370 32 %6 = load_const (0x00000003 = 0.000000)
371 32 %7 = deref_var &ubo_array (ubo int[4])
372 32 %8 = deref_array &(*%7)[3] (ubo int) // &ubo_array[3]
373 32 %9 = @load_deref (%8) (access=none)
374 32 %10 = load_const (0x00000002)
375 1 %11 = ieq %9, %10 (0x2)
376 // succs: b4
377 }
378 block b4: // preds: b2 b3
379 1 %12 = phi b3: %11, b2: %4
380 32 %13 = phi b3: %6 (0x3), b2: %5
381 1 %14 = ior %12, %3
382 // succs: b5 b6
383 if %14 {
384 block b5:// preds: b4
385 break
386 // succs: b8
387 } else {
388 block b6: // preds: b4, succs: b7
389 }
390 block b7: // preds: b6
391 32 %15 = deref_var &ubo_array (ubo int[4])
392 32 %16 = deref_array &(*%15)[%13] (ubo int) // &ubo_array[%13]
393 32 %17 = @load_deref (%16) (access=none)
394 32 %18 = deref_var &out (shader_out int)
395 @store_deref (%18, %17) (wrmask=x, access=none)
396 // succs: b1
397 }
398 block b8: // preds: b5, succs: b9
399 block b9:
400 }
401 )"));
402 }
403
TEST_F(nir_opt_loop_test,opt_loop_merge_terminators_skip_merge_if_phis)404 TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_skip_merge_if_phis)
405 {
406 /* Tests that opt_loop_merge_terminators skips merging the terminators if
407 * the loop has phis. We can update or remove this test if support for
408 * phis is added to this pass:
409 */
410 nir_deref_instr *deref = nir_build_deref_var(b, ubo_var);
411 nir_def *ubo_def = nir_load_deref(b, deref);
412
413 nir_loop *loop = nir_push_loop(b);
414
415 nir_if *term1;
416 nir_if *term2;
417 add_loop_terminators(&term1, &term2, false, false);
418
419 nir_pop_loop(b, loop);
420
421 create_loop_phis(loop, term1, term2, in_def, ubo_def);
422
423 ASSERT_FALSE(nir_opt_loop(b->shader));
424
425 nir_validate_shader(b->shader, NULL);
426
427 check_nir_string(NIR_REFERENCE_SHADER(R"(
428 shader: MESA_SHADER_FRAGMENT
429 name: nir_opt_loop_test
430 subgroup_size: 0
431 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
432 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
433 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
434 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
435 decl_function main () (entrypoint)
436
437 impl main {
438 block b0: // preds:
439 32 %0 = deref_var &in (shader_in int)
440 32 %1 = @load_deref (%0) (access=none)
441 32 %2 = deref_var &ubo1 (ubo int)
442 32 %3 = @load_deref (%2) (access=none)
443 // succs: b1
444 loop {
445 block b1: // preds: b0 b7
446 32 %4 = load_const (0x00000001)
447 1 %5 = ieq %1, %4 (0x1)
448 // succs: b2 b3
449 if %5 {
450 block b2:// preds: b1
451 break
452 // succs: b8
453 } else {
454 block b3: // preds: b1, succs: b4
455 }
456 block b4: // preds: b3
457 32 %6 = deref_var &ubo1 (ubo int)
458 32 %7 = @load_deref (%6) (access=none)
459 32 %8 = load_const (0x00000002)
460 1 %9 = ieq %7, %8 (0x2)
461 // succs: b5 b6
462 if %9 {
463 block b5:// preds: b4
464 break
465 // succs: b8
466 } else {
467 block b6: // preds: b4, succs: b7
468 }
469 block b7: // preds: b6, succs: b1
470 }
471 block b8: // preds: b2 b5
472 32 %10 = phi b2: %1, b5: %3
473 // succs: b9
474 block b9:
475 }
476 )"));
477 }
478
TEST_F(nir_opt_loop_test,opt_loop_merge_terminators_skip_merge_if_phis_nested_loop)479 TEST_F(nir_opt_loop_test, opt_loop_merge_terminators_skip_merge_if_phis_nested_loop)
480 {
481 /* Tests that opt_loop_merge_terminators skips merging the terminators if
482 * the loop has phis. We can update or remove this test if support for
483 * phis is added to this pass:
484 */
485 nir_deref_instr *deref = nir_build_deref_var(b, ubo_var);
486 nir_def *ubo_def = nir_load_deref(b, deref);
487
488 nir_loop *loop = nir_push_loop(b);
489
490 /* Add a nested loop to make sure we test the correct loop for trailing phis */
491 nir_loop *nested_loop = nir_push_loop(b);
492 nir_pop_loop(b, nested_loop);
493
494 nir_if *term1;
495 nir_if *term2;
496 add_loop_terminators(&term1, &term2, false, false);
497
498 nir_pop_loop(b, loop);
499
500 create_loop_phis(loop, term1, term2, in_def, ubo_def);
501
502 ASSERT_FALSE(nir_opt_loop(b->shader));
503
504 nir_validate_shader(b->shader, NULL);
505
506 check_nir_string(NIR_REFERENCE_SHADER(R"(
507 shader: MESA_SHADER_FRAGMENT
508 name: nir_opt_loop_test
509 subgroup_size: 0
510 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
511 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
512 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
513 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
514 decl_function main () (entrypoint)
515
516 impl main {
517 block b0: // preds:
518 32 %0 = deref_var &in (shader_in int)
519 32 %1 = @load_deref (%0) (access=none)
520 32 %2 = deref_var &ubo1 (ubo int)
521 32 %3 = @load_deref (%2) (access=none)
522 // succs: b1
523 loop {
524 block b1: // preds: b0 b9, succs: b2
525 loop {
526 block b2: // preds: b1 b2, succs: b2
527 }
528 block b3: // preds:
529 32 %4 = load_const (0x00000001)
530 1 %5 = ieq %1, %4 (0x1)
531 // succs: b4 b5
532 if %5 {
533 block b4:// preds: b3
534 break
535 // succs: b10
536 } else {
537 block b5: // preds: b3, succs: b6
538 }
539 block b6: // preds: b5
540 32 %6 = deref_var &ubo1 (ubo int)
541 32 %7 = @load_deref (%6) (access=none)
542 32 %8 = load_const (0x00000002)
543 1 %9 = ieq %7, %8 (0x2)
544 // succs: b7 b8
545 if %9 {
546 block b7:// preds: b6
547 break
548 // succs: b10
549 } else {
550 block b8: // preds: b6, succs: b9
551 }
552 block b9: // preds: b8, succs: b1
553 }
554 block b10: // preds: b4 b7
555 32 %10 = phi b4: %1, b7: %3
556 // succs: b11
557 block b11:
558 }
559 )"));
560 }
561
TEST_F(nir_opt_loop_test,opt_loop_peel_initial_break_ends_with_jump)562 TEST_F(nir_opt_loop_test, opt_loop_peel_initial_break_ends_with_jump)
563 {
564 nir_loop *loop = nir_push_loop(b);
565
566 /* the break we want to move down: */
567 nir_break_if(b, nir_imm_true(b));
568
569 /* do_work_2: */
570 nir_push_if(b, nir_imm_true(b));
571 nir_jump(b, nir_jump_continue);
572 nir_pop_if(b, NULL);
573 nir_jump(b, nir_jump_return);
574
575 nir_pop_loop(b, loop);
576
577 ASSERT_FALSE(nir_opt_loop(b->shader));
578
579 nir_validate_shader(b->shader, NULL);
580
581 check_nir_string(NIR_REFERENCE_SHADER(R"(
582 shader: MESA_SHADER_FRAGMENT
583 name: nir_opt_loop_test
584 subgroup_size: 0
585 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
586 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
587 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
588 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
589 decl_function main () (entrypoint)
590
591 impl main {
592 block b0: // preds:
593 32 %0 = deref_var &in (shader_in int)
594 32 %1 = @load_deref (%0) (access=none)
595 // succs: b1
596 loop {
597 block b1: // preds: b0 b5
598 1 %2 = load_const (true)
599 // succs: b2 b3
600 if %2 (true) {
601 block b2:// preds: b1
602 break
603 // succs: b8
604 } else {
605 block b3: // preds: b1, succs: b4
606 }
607 block b4: // preds: b3
608 1 %3 = load_const (true)
609 // succs: b5 b6
610 if %3 (true) {
611 block b5:// preds: b4
612 continue
613 // succs: b1
614 } else {
615 block b6: // preds: b4, succs: b7
616 }
617 block b7:// preds: b6
618 return
619 // succs: b9
620 }
621 block b8: // preds: b2, succs: b9
622 block b9:
623 }
624 )"));
625 }
626
TEST_F(nir_opt_loop_test,opt_loop_peel_initial_break_nontrivial_break)627 TEST_F(nir_opt_loop_test, opt_loop_peel_initial_break_nontrivial_break)
628 {
629 nir_loop *loop = nir_push_loop(b);
630
631 nir_push_if(b, nir_imm_true(b));
632
633 nir_push_if(b, nir_imm_true(b));
634 nir_push_if(b, nir_imm_true(b));
635 nir_jump(b, nir_jump_break);
636 nir_pop_if(b, NULL);
637 nir_pop_if(b, NULL);
638 nir_nop(b);
639
640 nir_jump(b, nir_jump_break);
641 nir_pop_if(b, NULL);
642
643 /* do_work_2: */
644 nir_nop(b);
645
646 nir_pop_loop(b, loop);
647
648 ASSERT_FALSE(nir_opt_loop(b->shader));
649
650 nir_validate_shader(b->shader, NULL);
651
652 check_nir_string(NIR_REFERENCE_SHADER(R"(
653 shader: MESA_SHADER_FRAGMENT
654 name: nir_opt_loop_test
655 subgroup_size: 0
656 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
657 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
658 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
659 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
660 decl_function main () (entrypoint)
661
662 impl main {
663 block b0: // preds:
664 32 %0 = deref_var &in (shader_in int)
665 32 %1 = @load_deref (%0) (access=none)
666 // succs: b1
667 loop {
668 block b1: // preds: b0 b10
669 1 %2 = load_const (true)
670 // succs: b2 b9
671 if %2 (true) {
672 block b2: // preds: b1
673 1 %3 = load_const (true)
674 // succs: b3 b7
675 if %3 (true) {
676 block b3: // preds: b2
677 1 %4 = load_const (true)
678 // succs: b4 b5
679 if %4 (true) {
680 block b4:// preds: b3
681 break
682 // succs: b11
683 } else {
684 block b5: // preds: b3, succs: b6
685 }
686 block b6: // preds: b5, succs: b8
687 } else {
688 block b7: // preds: b2, succs: b8
689 }
690 block b8:// preds: b6 b7
691 @nop
692 break
693 // succs: b11
694 } else {
695 block b9: // preds: b1, succs: b10
696 }
697 block b10:// preds: b9
698 @nop
699 // succs: b1
700 }
701 block b11: // preds: b4 b8, succs: b12
702 block b12:
703 }
704 )"));
705 }
706
TEST_F(nir_opt_loop_test,opt_loop_peel_initial_break_deref)707 TEST_F(nir_opt_loop_test, opt_loop_peel_initial_break_deref)
708 {
709 nir_loop *loop = nir_push_loop(b);
710
711 nir_deref_instr *var_deref = nir_build_deref_var(b, out_var);
712
713 nir_push_if(b, nir_imm_true(b));
714 nir_jump(b, nir_jump_break);
715 nir_pop_if(b, NULL);
716
717 nir_store_deref(b, var_deref, nir_imm_int(b, 42), 0x1);
718
719 nir_pop_loop(b, loop);
720
721 ASSERT_TRUE(nir_opt_loop(b->shader));
722
723 nir_validate_shader(b->shader, NULL);
724
725 check_nir_string(NIR_REFERENCE_SHADER(R"(
726 shader: MESA_SHADER_FRAGMENT
727 name: nir_opt_loop_test
728 subgroup_size: 0
729 decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0)
730 decl_var shader_out INTERP_MODE_NONE none int out (FRAG_RESULT_DEPTH.x, 0, 0)
731 decl_var ubo INTERP_MODE_NONE none int ubo1 (0, 0, 0)
732 decl_var ubo INTERP_MODE_NONE none int[4] ubo_array (0, 0, 0)
733 decl_function main () (entrypoint)
734
735 impl main {
736 block b0: // preds:
737 32 %0 = deref_var &in (shader_in int)
738 32 %1 = @load_deref (%0) (access=none)
739 1 %2 = load_const (true)
740 // succs: b1 b2
741 if %2 (true) {
742 block b1: // preds: b0, succs: b8
743 } else {
744 block b2: // preds: b0, succs: b3
745 loop {
746 block b3: // preds: b2 b6
747 32 %3 = load_const (0x0000002a = 42)
748 32 %4 = deref_var &out (shader_out int)
749 @store_deref (%4, %3 (0x2a)) (wrmask=x, access=none)
750 1 %5 = load_const (true)
751 // succs: b4 b5
752 if %5 (true) {
753 block b4:// preds: b3
754 break
755 // succs: b7
756 } else {
757 block b5: // preds: b3, succs: b6
758 }
759 block b6: // preds: b5, succs: b3
760 }
761 block b7: // preds: b4, succs: b8
762 }
763 block b8: // preds: b1 b7, succs: b9
764 block b9:
765 }
766 )"));
767 }
768