blob: 0713d49ab5274d6a0376b49d01214be97ee68f41 [file] [log] [blame]
/*
* Copyright © 2020 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "gtest/gtest.h"
#include "nir.h"
#include "nir_builder.h"
#include "nir_phi_builder.h"
#define UNROLL_TEST_INSERT(_label, _type, _init, _limit, _step, \
_cond, _incr, _rev, _exp_res, \
_exp_instr_count, _exp_loop_count) \
TEST_F(nir_loop_unroll_test, _label) \
{ \
nir_def *init = nir_imm_##_type(&bld, _init); \
nir_def *limit = nir_imm_##_type(&bld, _limit); \
nir_def *step = nir_imm_##_type(&bld, _step); \
loop_unroll_test_helper(&bld, init, limit, step, \
&nir_##_cond, &nir_##_incr, _rev); \
EXPECT_##_exp_res(nir_opt_loop_unroll(bld.shader)); \
EXPECT_EQ(_exp_instr_count, count_instr(nir_op_##_incr)); \
EXPECT_EQ(_exp_loop_count, count_loops()); \
}
#define UNROLL_TEST_UNKNOWN_INIT_INSERT(_label, __type, _limit, _step, \
_cond, _incr, _rev, _exp_res, \
_exp_instr_count, _exp_loop_count)\
TEST_F(nir_loop_unroll_test, _label) \
{ \
nir_def *one = nir_imm_int(&bld, 1); \
nir_def *twelve = nir_imm_int(&bld, 12); \
nir_def *init = nir_load_ubo(&bld, 1, 32, one, twelve, (gl_access_qualifier)0, 0, 0, 0, 16); \
nir_def *limit = nir_imm_##__type(&bld, _limit); \
nir_def *step = nir_imm_##__type(&bld, _step); \
loop_unroll_test_helper(&bld, init, limit, step, \
&nir_##_cond, &nir_##_incr, _rev); \
EXPECT_##_exp_res(nir_opt_loop_unroll(bld.shader)); \
EXPECT_EQ(_exp_instr_count, count_instr(nir_op_##_incr)); \
EXPECT_EQ(_exp_loop_count, count_loops()); \
}
namespace {
class nir_loop_unroll_test : public ::testing::Test {
protected:
nir_loop_unroll_test()
{
glsl_type_singleton_init_or_ref();
static nir_shader_compiler_options options = { };
options.max_unroll_iterations = 32;
options.force_indirect_unrolling_sampler = false;
options.force_indirect_unrolling = nir_var_all;
bld = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, &options,
"loop unrolling tests");
}
~nir_loop_unroll_test()
{
ralloc_free(bld.shader);
glsl_type_singleton_decref();
}
int count_instr(nir_op op);
int count_loops(void);
nir_builder bld;
};
} /* namespace */
int
nir_loop_unroll_test::count_instr(nir_op op)
{
int count = 0;
nir_foreach_block(block, bld.impl) {
nir_foreach_instr(instr, block) {
if (instr->type != nir_instr_type_alu)
continue;
nir_alu_instr *alu_instr = nir_instr_as_alu(instr);
if (alu_instr->op == op)
count++;
}
}
return count;
}
int
nir_loop_unroll_test::count_loops(void)
{
int count = 0;
foreach_list_typed(nir_cf_node, cf_node, node, &bld.impl->body) {
if (cf_node->type == nir_cf_node_loop)
count++;
}
return count;
}
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)
{
nir_loop *loop = nir_push_loop(bld);
nir_block *top_block =
nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node));
nir_block *head_block = nir_loop_first_block(loop);
nir_phi_instr *phi = nir_phi_instr_create(bld->shader);
nir_def_init(&phi->instr, &phi->def, 1, 32);
nir_phi_instr_add_src(phi, top_block, init);
nir_def *cond = cond_instr(bld,
(reverse ? limit : &phi->def),
(reverse ? &phi->def : limit));
nir_if *nif = nir_push_if(bld, cond);
nir_jump(bld, nir_jump_break);
nir_pop_if(bld, nif);
nir_def *var = incr_instr(bld, &phi->def, step);
nir_phi_instr_add_src(phi, nir_cursor_current_block(bld->cursor), var);
nir_pop_loop(bld, loop);
bld->cursor = nir_after_phis(head_block);
nir_builder_instr_insert(bld, &phi->instr);
nir_validate_shader(bld->shader, NULL);
}
UNROLL_TEST_INSERT(iadd, int, 0, 24, 4,
ige, iadd, false, TRUE, 6, 0)
UNROLL_TEST_INSERT(iadd_rev, int, 0, 24, 4,
ilt, iadd, true, TRUE, 7, 0)
UNROLL_TEST_INSERT(fadd, float, 0.0, 24.0, 4.0,
fge, fadd, false, TRUE, 6, 0)
UNROLL_TEST_INSERT(fadd_rev, float, 0.0, 24.0, 4.0,
flt, fadd, true, TRUE, 7, 0)
UNROLL_TEST_INSERT(imul, int, 1, 81, 3,
ige, imul, false, TRUE, 4, 0)
UNROLL_TEST_INSERT(imul_rev, int, 1, 81, 3,
ilt, imul, true, TRUE, 5, 0)
#if 0 /* Disable tests until support is re-enabled in loop_analyze. */
UNROLL_TEST_INSERT(fmul, float, 1.5, 81.0, 3.0,
fge, fmul, false, TRUE, 4, 0)
UNROLL_TEST_INSERT(fmul_rev, float, 1.0, 81.0, 3.0,
flt, fmul, true, TRUE, 5, 0)
#endif
UNROLL_TEST_INSERT(ishl, int, 1, 128, 1,
ige, ishl, false, TRUE, 7, 0)
UNROLL_TEST_INSERT(ishl_rev, int, 1, 128, 1,
ilt, ishl, true, TRUE, 8, 0)
UNROLL_TEST_INSERT(ishr, int, 64, 4, 1,
ilt, ishr, false, TRUE, 5, 0)
UNROLL_TEST_INSERT(ishr_rev, int, 64, 4, 1,
ige, ishr, true, TRUE, 4, 0)
UNROLL_TEST_INSERT(ushr, int, 64, 4, 1,
ilt, ushr, false, TRUE, 5, 0)
UNROLL_TEST_INSERT(ushr_rev, int, 64, 4, 1,
ige, ushr, true, TRUE, 4, 0)
UNROLL_TEST_INSERT(lshl_neg, int, 0xf0f0f0f0, 0, 1,
ige, ishl, false, TRUE, 4, 0)
UNROLL_TEST_INSERT(lshl_neg_rev, int, 0xf0f0f0f0, 0, 1,
ilt, ishl, true, TRUE, 4, 0)
UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_uge_unknown_init_gt, int, 4, 6,
uge, iadd, false, TRUE, 2, 0)
UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_uge_unknown_init_eq, int, 16, 4,
uge, iadd, false, TRUE, 5, 0)
UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_ugt_unknown_init_eq, int, 16, 4,
ult, iadd, true, TRUE, 6, 0)
UNROLL_TEST_UNKNOWN_INIT_INSERT(iadd_ige_unknown_init, int, 4, 6,
ige, iadd, false, FALSE, 1, 1)