From: Danylo Piliaiev Date: Tue, 20 Aug 2019 15:48:33 +0000 (+0300) Subject: nir/loop_analyze: Treat do{}while(false) loops as 0 iterations X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e71fc7f2387dc14d08b7b310c41d83aa7a84c3b4;p=mesa.git nir/loop_analyze: Treat do{}while(false) loops as 0 iterations Loops like: block block_0: vec1 32 ssa_2 = load_const (0x00000020) vec1 32 ssa_3 = load_const (0x00000001) loop { vec1 32 ssa_7 = phi block_0: ssa_3, block_4: ssa_9 vec1 1 ssa_8 = ige ssa_2, ssa_7 if ssa_8 { break } else { } vec1 32 ssa_9 = iadd ssa_7, ssa_1 } Were treated as having more than 1 iteration and after unrolling produced wrong results, however such loop will exit during the first iteration if not unrolled. So we check if loop will actually loop. Fixes tests/shaders/glsl-fs-loop-while-false-02.shader_test Signed-off-by: Danylo Piliaiev Reviewed-by: Timothy Arceri --- diff --git a/src/compiler/nir/nir_loop_analyze.c b/src/compiler/nir/nir_loop_analyze.c index 0ac04b82799..4689d2230af 100644 --- a/src/compiler/nir/nir_loop_analyze.c +++ b/src/compiler/nir/nir_loop_analyze.c @@ -647,6 +647,43 @@ get_iteration(nir_op cond_op, nir_const_value initial, nir_const_value step, return iter_u64 > INT_MAX ? -1 : (int)iter_u64; } +static bool +will_break_on_first_iteration(nir_const_value step, + nir_alu_type induction_base_type, + unsigned trip_offset, + nir_op cond_op, unsigned bit_size, + nir_const_value initial, + nir_const_value limit, + bool limit_rhs, bool invert_cond) +{ + if (trip_offset == 1) { + nir_op add_op; + switch (induction_base_type) { + case nir_type_float: + add_op = nir_op_fadd; + break; + case nir_type_int: + case nir_type_uint: + add_op = nir_op_iadd; + break; + default: + unreachable("Unhandled induction variable base type!"); + } + + initial = eval_const_binop(add_op, bit_size, initial, step); + } + + nir_const_value *src[2]; + src[limit_rhs ? 0 : 1] = &initial; + src[limit_rhs ? 1 : 0] = &limit; + + /* Evaluate the loop exit condition */ + nir_const_value result; + nir_eval_const_opcode(cond_op, &result, 1, bit_size, src); + + return invert_cond ? !result.b : result.b; +} + static bool test_iterations(int32_t iter_int, nir_const_value step, nir_const_value limit, nir_op cond_op, unsigned bit_size, @@ -741,6 +778,18 @@ calculate_iterations(nir_const_value initial, nir_const_value step, assert(nir_src_bit_size(alu->src[0].src) == nir_src_bit_size(alu->src[1].src)); unsigned bit_size = nir_src_bit_size(alu->src[0].src); + + /* get_iteration works under assumption that iterator will be + * incremented or decremented until it hits the limit, + * however if the loop condition is false on the first iteration + * get_iteration's assumption is broken. Handle such loops first. + */ + if (will_break_on_first_iteration(step, induction_base_type, trip_offset, + alu_op, bit_size, initial, + limit, limit_rhs, invert_cond)) { + return 0; + } + int iter_int = get_iteration(alu_op, initial, step, limit, bit_size); /* If iter_int is negative the loop is ill-formed or is the conditional is