| /* |
| * Copyright 2025 Valve Corporation |
| * SPDX-License-Identifier: MIT |
| */ |
| |
| #include "nir.h" |
| #include "nir_builder.h" |
| #include "nir_test.h" |
| |
| class nir_lower_discard_if_test : public nir_test { |
| protected: |
| nir_lower_discard_if_test(); |
| |
| nir_def *in_def; |
| |
| |
| }; |
| |
| nir_lower_discard_if_test::nir_lower_discard_if_test() |
| : nir_test::nir_test("nir_lower_discard_if_test", MESA_SHADER_FRAGMENT) |
| { |
| nir_variable *var = nir_variable_create(b->shader, nir_var_shader_in, glsl_int_type(), "in"); |
| in_def = nir_load_var(b, var); |
| } |
| |
| TEST_F(nir_lower_discard_if_test, move_single_terminate_out_of_loop) |
| { |
| nir_loop *loop = nir_push_loop(b); |
| nir_def *cmp_result = nir_ieq(b, in_def, nir_imm_zero(b, 1, 32)); |
| nir_break_if(b, cmp_result); |
| nir_terminate(b); |
| nir_pop_loop(b, loop); |
| |
| ASSERT_TRUE(nir_lower_discard_if(b->shader, nir_move_terminate_out_of_loops)); |
| |
| check_nir_string(NIR_REFERENCE_SHADER(R"( |
| shader: MESA_SHADER_FRAGMENT |
| name: nir_lower_discard_if_test |
| subgroup_size: 0 |
| decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0) |
| decl_function main () (entrypoint) |
| |
| impl main { |
| block b0: // preds: |
| 32 %0 = deref_var &in (shader_in int) |
| 32 %1 = @load_deref (%0) (access=none) |
| 1 %2 = load_const (false) |
| // succs: b1 |
| loop { |
| block b1: // preds: b0 b7 |
| 32 %3 = load_const (0x00000000) |
| 1 %4 = ieq %1, %3 (0x0) |
| // succs: b2 b3 |
| if %4 { |
| block b2:// preds: b1 |
| break |
| // succs: b8 |
| } else { |
| block b3: // preds: b1, succs: b4 |
| } |
| block b4: // preds: b3 |
| 1 %5 = load_const (true) |
| // succs: b5 b6 |
| if %5 (true) { |
| block b5:// preds: b4 |
| break |
| // succs: b8 |
| } else { |
| block b6: // preds: b4, succs: b7 |
| } |
| block b7: // preds: b6, succs: b1 |
| } |
| block b8: // preds: b2 b5 |
| 1 %6 = phi b2: %2 (false), b5: %5 (true) |
| @terminate_if (%6) |
| // succs: b9 |
| block b9: |
| } |
| )")); |
| } |
| |
| TEST_F(nir_lower_discard_if_test, move_multiple_terminate_out_of_loop) |
| { |
| nir_loop *loop = nir_push_loop(b); |
| nir_def *cmp_result = nir_ieq(b, in_def, nir_imm_zero(b, 1, 32)); |
| nir_terminate_if(b, cmp_result); |
| nir_def *cmp_result2 = nir_ieq(b, in_def, nir_imm_int(b, 1)); |
| nir_terminate_if(b, cmp_result2); |
| nir_jump(b, nir_jump_break); |
| nir_pop_loop(b, loop); |
| |
| ASSERT_TRUE(nir_lower_discard_if(b->shader, nir_move_terminate_out_of_loops)); |
| |
| check_nir_string(NIR_REFERENCE_SHADER(R"( |
| shader: MESA_SHADER_FRAGMENT |
| name: nir_lower_discard_if_test |
| subgroup_size: 0 |
| decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0) |
| decl_function main () (entrypoint) |
| |
| impl main { |
| block b0: // preds: |
| 1 %0 = undefined |
| 32 %1 = deref_var &in (shader_in int) |
| 32 %2 = @load_deref (%1) (access=none) |
| 1 %3 = load_const (false) |
| 1 %4 = load_const (false) |
| // succs: b1 |
| loop { |
| block b1: // preds: b0 |
| 32 %5 = load_const (0x00000000) |
| 1 %6 = ieq %2, %5 (0x0) |
| // succs: b2 b3 |
| if %6 { |
| block b2:// preds: b1 |
| break |
| // succs: b8 |
| } else { |
| block b3: // preds: b1, succs: b4 |
| } |
| block b4: // preds: b3 |
| 32 %7 = load_const (0x00000001) |
| 1 %8 = ieq %2, %7 (0x1) |
| // succs: b5 b6 |
| if %8 { |
| block b5:// preds: b4 |
| break |
| // succs: b8 |
| } else { |
| block b6: // preds: b4, succs: b7 |
| } |
| block b7:// preds: b6 |
| break |
| // succs: b8 |
| } |
| block b8: // preds: b2 b5 b7 |
| 1 %9 = phi b2: %6, b5: %0, b7: %3 (false) |
| 1 %10 = phi b2: %4 (false), b5: %8, b7: %4 (false) |
| @terminate_if (%10) |
| @terminate_if (%9) |
| // succs: b9 |
| block b9: |
| } |
| )")); |
| } |
| |
| TEST_F(nir_lower_discard_if_test, move_terminate_out_of_nested_loop) |
| { |
| nir_loop *loop = nir_push_loop(b); |
| { |
| nir_def *cmp_result = nir_ieq(b, in_def, nir_imm_zero(b, 1, 32)); |
| nir_break_if(b, cmp_result); |
| nir_loop *inner = nir_push_loop(b); |
| { |
| nir_def *cmp_result2 = nir_ieq(b, in_def, nir_imm_int(b, 1)); |
| nir_terminate_if(b, cmp_result2); |
| nir_jump(b, nir_jump_break); |
| } |
| nir_pop_loop(b, inner); |
| } |
| nir_pop_loop(b, loop); |
| |
| ASSERT_TRUE(nir_lower_discard_if(b->shader, nir_move_terminate_out_of_loops)); |
| |
| check_nir_string(NIR_REFERENCE_SHADER(R"( |
| shader: MESA_SHADER_FRAGMENT |
| name: nir_lower_discard_if_test |
| subgroup_size: 0 |
| decl_var shader_in INTERP_MODE_SMOOTH none int in (VARYING_SLOT_POS.x, 0, 0) |
| decl_function main () (entrypoint) |
| |
| impl main { |
| block b0: // preds: |
| 32 %0 = deref_var &in (shader_in int) |
| 32 %1 = @load_deref (%0) (access=none) |
| 1 %2 = load_const (false) |
| // succs: b1 |
| loop { |
| block b1: // preds: b0 b12 |
| 32 %3 = load_const (0x00000000) |
| 1 %4 = ieq %1, %3 (0x0) |
| // succs: b2 b3 |
| if %4 { |
| block b2:// preds: b1 |
| break |
| // succs: b13 |
| } else { |
| block b3: // preds: b1, succs: b4 |
| } |
| block b4: // preds: b3 |
| 1 %5 = load_const (false) |
| // succs: b5 |
| loop { |
| block b5: // preds: b4 |
| 32 %6 = load_const (0x00000001) |
| 1 %7 = ieq %1, %6 (0x1) |
| // succs: b6 b7 |
| if %7 { |
| block b6:// preds: b5 |
| break |
| // succs: b9 |
| } else { |
| block b7: // preds: b5, succs: b8 |
| } |
| block b8:// preds: b7 |
| break |
| // succs: b9 |
| } |
| block b9: // preds: b6 b8 |
| 1 %8 = phi b6: %7, b8: %5 (false) |
| // succs: b10 b11 |
| if %8 { |
| block b10:// preds: b9 |
| break |
| // succs: b13 |
| } else { |
| block b11: // preds: b9, succs: b12 |
| } |
| block b12: // preds: b11, succs: b1 |
| } |
| block b13: // preds: b2 b10 |
| 1 %9 = phi b2: %2 (false), b10: %8 |
| @terminate_if (%9) |
| // succs: b14 |
| block b14: |
| } |
| )")); |
| } |