• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define UNROLL_TEST_UNKNOWN_INIT_INSERT(_label, __type, _limit, _step,    \
45                                         _cond, _incr, _rev, _exp_res,     \
46                                         _exp_instr_count, _exp_loop_count)\
47    TEST_F(nir_loop_unroll_test, _label)                                   \
48    {                                                                      \
49       nir_def *one = nir_imm_int(&bld, 1);                                \
50       nir_def *twelve = nir_imm_int(&bld, 12);                            \
51       nir_def *init = nir_load_ubo(&bld, 1, 32, one, twelve, (gl_access_qualifier)0, 0, 0, 0, 16); \
52       nir_def *limit = nir_imm_##__type(&bld, _limit);                    \
53       nir_def *step = nir_imm_##__type(&bld, _step);                      \
54       loop_unroll_test_helper(&bld, init, limit, step,                    \
55                               &nir_##_cond, &nir_##_incr, _rev);          \
56       EXPECT_##_exp_res(nir_opt_loop_unroll(bld.shader));                 \
57       EXPECT_EQ(_exp_instr_count, count_instr(nir_op_##_incr));           \
58       EXPECT_EQ(_exp_loop_count, count_loops());                          \
59    }
60 
61 
62 namespace {
63 
64 class nir_loop_unroll_test : public ::testing::Test {
65 protected:
nir_loop_unroll_test()66    nir_loop_unroll_test()
67    {
68       glsl_type_singleton_init_or_ref();
69       static nir_shader_compiler_options options = { };
70       options.max_unroll_iterations = 32;
71       options.force_indirect_unrolling_sampler = false;
72       options.force_indirect_unrolling = nir_var_all;
73       bld = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, &options,
74                                            "loop unrolling tests");
75    }
~nir_loop_unroll_test()76    ~nir_loop_unroll_test()
77    {
78       ralloc_free(bld.shader);
79       glsl_type_singleton_decref();
80    }
81 
82    int count_instr(nir_op op);
83    int count_loops(void);
84 
85    nir_builder bld;
86 };
87 
88 } /* namespace */
89 
90 int
count_instr(nir_op op)91 nir_loop_unroll_test::count_instr(nir_op op)
92 {
93    int count = 0;
94    nir_foreach_block(block, bld.impl) {
95       nir_foreach_instr(instr, block) {
96          if (instr->type != nir_instr_type_alu)
97             continue;
98          nir_alu_instr *alu_instr = nir_instr_as_alu(instr);
99          if (alu_instr->op == op)
100             count++;
101       }
102    }
103 
104    return count;
105 }
106 
107 int
count_loops(void)108 nir_loop_unroll_test::count_loops(void)
109 {
110    int count = 0;
111    foreach_list_typed(nir_cf_node, cf_node, node, &bld.impl->body) {
112       if (cf_node->type == nir_cf_node_loop)
113          count++;
114    }
115 
116    return count;
117 }
118 
119 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)120 loop_unroll_test_helper(nir_builder *bld, nir_def *init,
121                         nir_def *limit, nir_def *step,
122                         nir_def* (*cond_instr)(nir_builder*,
123                                                    nir_def*,
124                                                    nir_def*),
125                         nir_def* (*incr_instr)(nir_builder*,
126                                                    nir_def*,
127                                                    nir_def*),
128                         bool reverse)
129 {
130    nir_loop *loop = nir_push_loop(bld);
131 
132    nir_block *top_block =
133       nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
134    nir_block *head_block = nir_loop_first_block(loop);
135 
136    nir_phi_instr *phi = nir_phi_instr_create(bld->shader);
137    nir_def_init(&phi->instr, &phi->def, 1, 32);
138 
139    nir_phi_instr_add_src(phi, top_block, init);
140 
141    nir_def *cond = cond_instr(bld,
142                                   (reverse ? limit : &phi->def),
143                                   (reverse ? &phi->def : limit));
144 
145    nir_if *nif = nir_push_if(bld, cond);
146    nir_jump(bld, nir_jump_break);
147    nir_pop_if(bld, nif);
148 
149    nir_def *var = incr_instr(bld, &phi->def, step);
150 
151    nir_phi_instr_add_src(phi, nir_cursor_current_block(bld->cursor), var);
152 
153    nir_pop_loop(bld, loop);
154 
155    bld->cursor = nir_after_phis(head_block);
156    nir_builder_instr_insert(bld, &phi->instr);
157 
158    nir_validate_shader(bld->shader, NULL);
159 }
160 
161 UNROLL_TEST_INSERT(iadd,     int,   0,     24,   4,
162                    ige,      iadd,  false, TRUE, 6, 0)
163 UNROLL_TEST_INSERT(iadd_rev, int,   0,     24,   4,
164                    ilt,      iadd,  true,  TRUE, 7, 0)
165 UNROLL_TEST_INSERT(fadd,     float, 0.0,   24.0, 4.0,
166                    fge,      fadd,  false, TRUE, 6, 0)
167 UNROLL_TEST_INSERT(fadd_rev, float, 0.0,   24.0, 4.0,
168                    flt,      fadd,  true,  TRUE, 7, 0)
169 UNROLL_TEST_INSERT(imul,     int,   1,     81,   3,
170                    ige,      imul,  false, TRUE, 4, 0)
171 UNROLL_TEST_INSERT(imul_rev, int,   1,     81,   3,
172                    ilt,      imul,  true,  TRUE, 5, 0)
173 #if 0 /* Disable tests until support is re-enabled in loop_analyze. */
174 UNROLL_TEST_INSERT(fmul,     float, 1.5,   81.0, 3.0,
175                    fge,      fmul,  false, TRUE, 4, 0)
176 UNROLL_TEST_INSERT(fmul_rev, float, 1.0,   81.0, 3.0,
177                    flt,      fmul,  true,  TRUE, 5, 0)
178 #endif
179 UNROLL_TEST_INSERT(ishl,     int,   1,     128,  1,
180                    ige,      ishl,  false, TRUE, 7, 0)
181 UNROLL_TEST_INSERT(ishl_rev, int,   1,     128,  1,
182                    ilt,      ishl,  true,  TRUE, 8, 0)
183 UNROLL_TEST_INSERT(ishr,     int,   64,    4,    1,
184                    ilt,      ishr,  false, TRUE, 5, 0)
185 UNROLL_TEST_INSERT(ishr_rev, int,   64,    4,    1,
186                    ige,      ishr,  true,  TRUE, 4, 0)
187 UNROLL_TEST_INSERT(ushr,     int,   64,    4,    1,
188                    ilt,      ushr,  false, TRUE, 5, 0)
189 UNROLL_TEST_INSERT(ushr_rev, int,   64,    4,    1,
190                    ige,      ushr,  true,  TRUE, 4, 0)
191 
192 UNROLL_TEST_INSERT(lshl_neg,     int,  0xf0f0f0f0, 0,    1,
193                    ige,          ishl, false,      TRUE, 4, 0)
194 UNROLL_TEST_INSERT(lshl_neg_rev, int,  0xf0f0f0f0, 0,    1,
195                    ilt,          ishl, true,       TRUE, 4, 0)
196 
197 UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_uge_unknown_init_gt, int, 4, 6,
198                                 uge, iadd, false, TRUE, 2, 0)
199 UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_uge_unknown_init_eq, int, 16, 4,
200                                 uge, iadd, false, TRUE, 5, 0)
201 UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_ugt_unknown_init_eq, int, 16, 4,
202                                 ult, iadd, true, TRUE, 6, 0)
203 UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_ige_unknown_init, int, 4, 6,
204                                 ige, iadd, false, FALSE, 1, 1)
205