1 /*
2 * Copyright © 2020 Intel 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 "gtest/gtest.h"
25 #include "nir.h"
26 #include "nir_builder.h"
27 #include "nir_phi_builder.h"
28
29 #define UNROLL_TEST_INSERT(_label, _type, _init, _limit, _step, \
30 _cond, _incr, _rev, _exp_res, \
31 _exp_instr_count, _exp_loop_count) \
32 TEST_F(nir_loop_unroll_test, _label) \
33 { \
34 nir_def *init = nir_imm_##_type(&bld, _init); \
35 nir_def *limit = nir_imm_##_type(&bld, _limit); \
36 nir_def *step = nir_imm_##_type(&bld, _step); \
37 loop_unroll_test_helper(&bld, init, limit, step, \
38 &nir_##_cond, &nir_##_incr, _rev); \
39 EXPECT_##_exp_res(nir_opt_loop_unroll(bld.shader)); \
40 EXPECT_EQ(_exp_instr_count, count_instr(nir_op_##_incr)); \
41 EXPECT_EQ(_exp_loop_count, count_loops()); \
42 }
43
44 namespace {
45
46 class nir_loop_unroll_test : public ::testing::Test {
47 protected:
nir_loop_unroll_test()48 nir_loop_unroll_test()
49 {
50 glsl_type_singleton_init_or_ref();
51 static nir_shader_compiler_options options = { };
52 options.max_unroll_iterations = 32;
53 options.force_indirect_unrolling_sampler = false;
54 options.force_indirect_unrolling = nir_var_all;
55 bld = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, &options,
56 "loop unrolling tests");
57 }
~nir_loop_unroll_test()58 ~nir_loop_unroll_test()
59 {
60 ralloc_free(bld.shader);
61 glsl_type_singleton_decref();
62 }
63
64 int count_instr(nir_op op);
65 int count_loops(void);
66
67 nir_builder bld;
68 };
69
70 } /* namespace */
71
72 int
count_instr(nir_op op)73 nir_loop_unroll_test::count_instr(nir_op op)
74 {
75 int count = 0;
76 nir_foreach_block(block, bld.impl) {
77 nir_foreach_instr(instr, block) {
78 if (instr->type != nir_instr_type_alu)
79 continue;
80 nir_alu_instr *alu_instr = nir_instr_as_alu(instr);
81 if (alu_instr->op == op)
82 count++;
83 }
84 }
85
86 return count;
87 }
88
89 int
count_loops(void)90 nir_loop_unroll_test::count_loops(void)
91 {
92 int count = 0;
93 foreach_list_typed(nir_cf_node, cf_node, node, &bld.impl->body) {
94 if (cf_node->type == nir_cf_node_loop)
95 count++;
96 }
97
98 return count;
99 }
100
101 void
loop_unroll_test_helper(nir_builder * bld,nir_def * init,nir_def * limit,nir_def * step,nir_def * (* cond_instr)(nir_builder *,nir_def *,nir_def *),nir_def * (* incr_instr)(nir_builder *,nir_def *,nir_def *),bool reverse)102 loop_unroll_test_helper(nir_builder *bld, nir_def *init,
103 nir_def *limit, nir_def *step,
104 nir_def* (*cond_instr)(nir_builder*,
105 nir_def*,
106 nir_def*),
107 nir_def* (*incr_instr)(nir_builder*,
108 nir_def*,
109 nir_def*),
110 bool reverse)
111 {
112 nir_loop *loop = nir_push_loop(bld);
113
114 nir_block *top_block =
115 nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
116 nir_block *head_block = nir_loop_first_block(loop);
117
118 nir_phi_instr *phi = nir_phi_instr_create(bld->shader);
119 nir_def_init(&phi->instr, &phi->def, 1, 32);
120
121 nir_phi_instr_add_src(phi, top_block, init);
122
123 nir_def *cond = cond_instr(bld,
124 (reverse ? limit : &phi->def),
125 (reverse ? &phi->def : limit));
126
127 nir_if *nif = nir_push_if(bld, cond);
128 nir_jump(bld, nir_jump_break);
129 nir_pop_if(bld, nif);
130
131 nir_def *var = incr_instr(bld, &phi->def, step);
132
133 nir_phi_instr_add_src(phi, nir_cursor_current_block(bld->cursor), var);
134
135 nir_pop_loop(bld, loop);
136
137 bld->cursor = nir_after_phis(head_block);
138 nir_builder_instr_insert(bld, &phi->instr);
139
140 nir_validate_shader(bld->shader, NULL);
141 }
142
143 UNROLL_TEST_INSERT(iadd, int, 0, 24, 4,
144 ige, iadd, false, TRUE, 6, 0)
145 UNROLL_TEST_INSERT(iadd_rev, int, 0, 24, 4,
146 ilt, iadd, true, TRUE, 7, 0)
147 UNROLL_TEST_INSERT(fadd, float, 0.0, 24.0, 4.0,
148 fge, fadd, false, TRUE, 6, 0)
149 UNROLL_TEST_INSERT(fadd_rev, float, 0.0, 24.0, 4.0,
150 flt, fadd, true, TRUE, 7, 0)
151 UNROLL_TEST_INSERT(imul, int, 1, 81, 3,
152 ige, imul, false, TRUE, 4, 0)
153 UNROLL_TEST_INSERT(imul_rev, int, 1, 81, 3,
154 ilt, imul, true, TRUE, 5, 0)
155 #if 0 /* Disable tests until support is re-enabled in loop_analyze. */
156 UNROLL_TEST_INSERT(fmul, float, 1.5, 81.0, 3.0,
157 fge, fmul, false, TRUE, 4, 0)
158 UNROLL_TEST_INSERT(fmul_rev, float, 1.0, 81.0, 3.0,
159 flt, fmul, true, TRUE, 5, 0)
160 #endif
161 UNROLL_TEST_INSERT(ishl, int, 1, 128, 1,
162 ige, ishl, false, TRUE, 7, 0)
163 UNROLL_TEST_INSERT(ishl_rev, int, 1, 128, 1,
164 ilt, ishl, true, TRUE, 8, 0)
165 UNROLL_TEST_INSERT(ishr, int, 64, 4, 1,
166 ilt, ishr, false, TRUE, 5, 0)
167 UNROLL_TEST_INSERT(ishr_rev, int, 64, 4, 1,
168 ige, ishr, true, TRUE, 4, 0)
169 UNROLL_TEST_INSERT(ushr, int, 64, 4, 1,
170 ilt, ushr, false, TRUE, 5, 0)
171 UNROLL_TEST_INSERT(ushr_rev, int, 64, 4, 1,
172 ige, ushr, true, TRUE, 4, 0)
173
174 UNROLL_TEST_INSERT(lshl_neg, int, 0xf0f0f0f0, 0, 1,
175 ige, ishl, false, TRUE, 4, 0)
176 UNROLL_TEST_INSERT(lshl_neg_rev, int, 0xf0f0f0f0, 0, 1,
177 ilt, ishl, true, TRUE, 4, 0)
178