1 /*
2 * Copyright © 2018 Intel Corporation
3 * Copyright © 2021 Valve Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "nir_test.h"
26
27 namespace {
28
29 class algebraic_test_base : public nir_test {
30 protected:
31 algebraic_test_base();
32
33 virtual void run_pass()=0;
34
35 void test_op(nir_op op, nir_def *src0, nir_def *src1, nir_def *src2,
36 nir_def *src3, const char *desc);
37
38 void test_2src_op(nir_op op, int64_t src0, int64_t src1);
39
40 nir_variable *res_var;
41 };
42
algebraic_test_base()43 algebraic_test_base::algebraic_test_base()
44 : nir_test::nir_test("nir_opt_algebraic_test")
45 {
46 res_var = nir_local_variable_create(b->impl, glsl_int_type(), "res");
47 }
48
test_op(nir_op op,nir_def * src0,nir_def * src1,nir_def * src2,nir_def * src3,const char * desc)49 void algebraic_test_base::test_op(nir_op op, nir_def *src0, nir_def *src1,
50 nir_def *src2, nir_def *src3, const char *desc)
51 {
52 nir_def *res_deref = &nir_build_deref_var(b, res_var)->def;
53
54 /* create optimized expression */
55 nir_intrinsic_instr *optimized_instr = nir_build_store_deref(
56 b, res_deref, nir_build_alu(b, op, src0, src1, src2, src3), 0x1);
57
58 run_pass();
59 b->cursor = nir_after_cf_list(&b->impl->body);
60
61 /* create reference expression */
62 nir_intrinsic_instr *ref_instr = nir_build_store_deref(
63 b, res_deref, nir_build_alu(b, op, src0, src1, src2, src3), 0x1);
64
65 /* test equality */
66 nir_opt_constant_folding(b->shader);
67
68 ASSERT_TRUE(nir_src_is_const(ref_instr->src[1]));
69 ASSERT_TRUE(nir_src_is_const(optimized_instr->src[1]));
70
71 int32_t ref = nir_src_as_int(ref_instr->src[1]);
72 int32_t optimized = nir_src_as_int(optimized_instr->src[1]);
73
74 EXPECT_EQ(ref, optimized) << "Test input: " << desc;
75
76 /* reset shader */
77 exec_list_make_empty(&nir_start_block(b->impl)->instr_list);
78 b->cursor = nir_after_cf_list(&b->impl->body);
79 }
80
test_2src_op(nir_op op,int64_t src0,int64_t src1)81 void algebraic_test_base::test_2src_op(nir_op op, int64_t src0, int64_t src1)
82 {
83 char desc[128];
84 snprintf(desc, sizeof(desc), "%s(%" PRId64 ", %" PRId64 ")", nir_op_infos[op].name, src0, src1);
85 test_op(op, nir_imm_int(b, src0), nir_imm_int(b, src1), NULL, NULL, desc);
86 }
87
88 class nir_opt_algebraic_test : public algebraic_test_base {
89 protected:
run_pass()90 virtual void run_pass() {
91 nir_opt_algebraic(b->shader);
92 }
93 };
94
95 class nir_opt_idiv_const_test : public algebraic_test_base {
96 protected:
run_pass()97 virtual void run_pass() {
98 nir_opt_idiv_const(b->shader, 8);
99 }
100 };
101
TEST_F(nir_opt_algebraic_test,umod_pow2_src2)102 TEST_F(nir_opt_algebraic_test, umod_pow2_src2)
103 {
104 for (int i = 0; i <= 9; i++)
105 test_2src_op(nir_op_umod, i, 4);
106 test_2src_op(nir_op_umod, UINT32_MAX, 4);
107 }
108
TEST_F(nir_opt_algebraic_test,imod_pow2_src2)109 TEST_F(nir_opt_algebraic_test, imod_pow2_src2)
110 {
111 for (int i = -9; i <= 9; i++) {
112 test_2src_op(nir_op_imod, i, 4);
113 test_2src_op(nir_op_imod, i, -4);
114 test_2src_op(nir_op_imod, i, INT32_MIN);
115 }
116 test_2src_op(nir_op_imod, INT32_MAX, 4);
117 test_2src_op(nir_op_imod, INT32_MAX, -4);
118 test_2src_op(nir_op_imod, INT32_MIN, 4);
119 test_2src_op(nir_op_imod, INT32_MIN, -4);
120 test_2src_op(nir_op_imod, INT32_MIN, INT32_MIN);
121 }
122
TEST_F(nir_opt_algebraic_test,irem_pow2_src2)123 TEST_F(nir_opt_algebraic_test, irem_pow2_src2)
124 {
125 for (int i = -9; i <= 9; i++) {
126 test_2src_op(nir_op_irem, i, 4);
127 test_2src_op(nir_op_irem, i, -4);
128 }
129 test_2src_op(nir_op_irem, INT32_MAX, 4);
130 test_2src_op(nir_op_irem, INT32_MAX, -4);
131 test_2src_op(nir_op_irem, INT32_MIN, 4);
132 test_2src_op(nir_op_irem, INT32_MIN, -4);
133 }
134
TEST_F(nir_opt_algebraic_test,msad)135 TEST_F(nir_opt_algebraic_test, msad)
136 {
137 options.lower_bitfield_extract = true;
138 options.has_bfe = true;
139 options.has_msad = true;
140
141 nir_def *src0 = nir_load_var(b, nir_local_variable_create(b->impl, glsl_int_type(), "src0"));
142 nir_def *src1 = nir_load_var(b, nir_local_variable_create(b->impl, glsl_int_type(), "src1"));
143
144 /* This mimics the sequence created by vkd3d-proton. */
145 nir_def *res = NULL;
146 for (unsigned i = 0; i < 4; i++) {
147 nir_def *ref = nir_ubitfield_extract(b, src0, nir_imm_int(b, i * 8), nir_imm_int(b, 8));
148 nir_def *src = nir_ubitfield_extract(b, src1, nir_imm_int(b, i * 8), nir_imm_int(b, 8));
149 nir_def *is_ref_zero = nir_ieq_imm(b, ref, 0);
150 nir_def *abs_diff = nir_iabs(b, nir_isub(b, ref, src));
151 nir_def *masked_diff = nir_bcsel(b, is_ref_zero, nir_imm_int(b, 0), abs_diff);
152 if (res)
153 res = nir_iadd(b, res, masked_diff);
154 else
155 res = masked_diff;
156 }
157
158 nir_store_var(b, res_var, res, 0x1);
159
160 while (nir_opt_algebraic(b->shader)) {
161 nir_opt_constant_folding(b->shader);
162 nir_opt_dce(b->shader);
163 }
164
165 unsigned count = 0;
166 nir_foreach_instr(instr, nir_start_block(b->impl)) {
167 if (instr->type == nir_instr_type_alu) {
168 ASSERT_TRUE(nir_instr_as_alu(instr)->op == nir_op_msad_4x8);
169 ASSERT_EQ(count, 0);
170 count++;
171 }
172 }
173 }
174
TEST_F(nir_opt_idiv_const_test,umod)175 TEST_F(nir_opt_idiv_const_test, umod)
176 {
177 for (uint32_t d : {16u, 17u, 0u, UINT32_MAX}) {
178 for (int i = 0; i <= 40; i++)
179 test_2src_op(nir_op_umod, i, d);
180 for (int i = 0; i < 20; i++)
181 test_2src_op(nir_op_umod, UINT32_MAX - i, d);
182 }
183 }
184
TEST_F(nir_opt_idiv_const_test,imod)185 TEST_F(nir_opt_idiv_const_test, imod)
186 {
187 for (int32_t d : {16, -16, 17, -17, 0, INT32_MIN, INT32_MAX}) {
188 for (int i = -40; i <= 40; i++)
189 test_2src_op(nir_op_imod, i, d);
190 for (int i = 0; i < 20; i++)
191 test_2src_op(nir_op_imod, INT32_MIN + i, d);
192 for (int i = 0; i < 20; i++)
193 test_2src_op(nir_op_imod, INT32_MAX - i, d);
194 }
195 }
196
TEST_F(nir_opt_idiv_const_test,irem)197 TEST_F(nir_opt_idiv_const_test, irem)
198 {
199 for (int32_t d : {16, -16, 17, -17, 0, INT32_MIN, INT32_MAX}) {
200 for (int i = -40; i <= 40; i++)
201 test_2src_op(nir_op_irem, i, d);
202 for (int i = 0; i < 20; i++)
203 test_2src_op(nir_op_irem, INT32_MIN + i, d);
204 for (int i = 0; i < 20; i++)
205 test_2src_op(nir_op_irem, INT32_MAX - i, d);
206 }
207 }
208
209 }
210