1 /*
2 * Copyright © 2018 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
26 #include "nir.h"
27 #include "nir_builder.h"
28
29 namespace {
30
31 class nir_vars_test : public ::testing::Test {
32 protected:
33 nir_vars_test();
34 ~nir_vars_test();
35
create_var(nir_variable_mode mode,const glsl_type * type,const char * name)36 nir_variable *create_var(nir_variable_mode mode, const glsl_type *type,
37 const char *name) {
38 if (mode == nir_var_function_temp)
39 return nir_local_variable_create(b->impl, type, name);
40 else
41 return nir_variable_create(b->shader, mode, type, name);
42 }
43
create_int(nir_variable_mode mode,const char * name)44 nir_variable *create_int(nir_variable_mode mode, const char *name) {
45 return create_var(mode, glsl_int_type(), name);
46 }
47
create_ivec2(nir_variable_mode mode,const char * name)48 nir_variable *create_ivec2(nir_variable_mode mode, const char *name) {
49 return create_var(mode, glsl_vector_type(GLSL_TYPE_INT, 2), name);
50 }
51
create_ivec4(nir_variable_mode mode,const char * name)52 nir_variable *create_ivec4(nir_variable_mode mode, const char *name) {
53 return create_var(mode, glsl_vector_type(GLSL_TYPE_INT, 4), name);
54 }
55
create_many_int(nir_variable_mode mode,const char * prefix,unsigned count)56 nir_variable **create_many_int(nir_variable_mode mode, const char *prefix, unsigned count) {
57 nir_variable **result = (nir_variable **)linear_alloc_child(lin_ctx, sizeof(nir_variable *) * count);
58 for (unsigned i = 0; i < count; i++)
59 result[i] = create_int(mode, linear_asprintf(lin_ctx, "%s%u", prefix, i));
60 return result;
61 }
62
create_many_ivec2(nir_variable_mode mode,const char * prefix,unsigned count)63 nir_variable **create_many_ivec2(nir_variable_mode mode, const char *prefix, unsigned count) {
64 nir_variable **result = (nir_variable **)linear_alloc_child(lin_ctx, sizeof(nir_variable *) * count);
65 for (unsigned i = 0; i < count; i++)
66 result[i] = create_ivec2(mode, linear_asprintf(lin_ctx, "%s%u", prefix, i));
67 return result;
68 }
69
create_many_ivec4(nir_variable_mode mode,const char * prefix,unsigned count)70 nir_variable **create_many_ivec4(nir_variable_mode mode, const char *prefix, unsigned count) {
71 nir_variable **result = (nir_variable **)linear_alloc_child(lin_ctx, sizeof(nir_variable *) * count);
72 for (unsigned i = 0; i < count; i++)
73 result[i] = create_ivec4(mode, linear_asprintf(lin_ctx, "%s%u", prefix, i));
74 return result;
75 }
76
77 unsigned count_derefs(nir_deref_type deref_type);
78 unsigned count_intrinsics(nir_intrinsic_op intrinsic);
count_function_temp_vars(void)79 unsigned count_function_temp_vars(void) {
80 return exec_list_length(&b->impl->locals);
81 }
82
count_shader_temp_vars(void)83 unsigned count_shader_temp_vars(void) {
84 unsigned count = 0;
85 nir_foreach_variable_with_modes(var, b->shader, nir_var_shader_temp)
86 count++;
87 return count;
88 }
89
90 nir_intrinsic_instr *get_intrinsic(nir_intrinsic_op intrinsic,
91 unsigned index);
92
93 nir_deref_instr *get_deref(nir_deref_type deref_type,
94 unsigned index);
95 void *lin_ctx;
96
97 nir_builder *b, _b;
98 };
99
nir_vars_test()100 nir_vars_test::nir_vars_test()
101 {
102 glsl_type_singleton_init_or_ref();
103
104 static const nir_shader_compiler_options options = { };
105 _b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, &options,
106 "vars test");
107 b = &_b;
108 lin_ctx = linear_alloc_parent(b->shader, 0);
109 }
110
~nir_vars_test()111 nir_vars_test::~nir_vars_test()
112 {
113 if (HasFailure()) {
114 printf("\nShader from the failed test:\n\n");
115 nir_print_shader(b->shader, stdout);
116 }
117
118 ralloc_free(b->shader);
119
120 glsl_type_singleton_decref();
121 }
122
123 unsigned
count_intrinsics(nir_intrinsic_op intrinsic)124 nir_vars_test::count_intrinsics(nir_intrinsic_op intrinsic)
125 {
126 unsigned count = 0;
127 nir_foreach_block(block, b->impl) {
128 nir_foreach_instr(instr, block) {
129 if (instr->type != nir_instr_type_intrinsic)
130 continue;
131 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
132 if (intrin->intrinsic == intrinsic)
133 count++;
134 }
135 }
136 return count;
137 }
138
139 unsigned
count_derefs(nir_deref_type deref_type)140 nir_vars_test::count_derefs(nir_deref_type deref_type)
141 {
142 unsigned count = 0;
143 nir_foreach_block(block, b->impl) {
144 nir_foreach_instr(instr, block) {
145 if (instr->type != nir_instr_type_deref)
146 continue;
147 nir_deref_instr *intrin = nir_instr_as_deref(instr);
148 if (intrin->deref_type == deref_type)
149 count++;
150 }
151 }
152 return count;
153 }
154
155 nir_intrinsic_instr *
get_intrinsic(nir_intrinsic_op intrinsic,unsigned index)156 nir_vars_test::get_intrinsic(nir_intrinsic_op intrinsic,
157 unsigned index)
158 {
159 nir_foreach_block(block, b->impl) {
160 nir_foreach_instr(instr, block) {
161 if (instr->type != nir_instr_type_intrinsic)
162 continue;
163 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
164 if (intrin->intrinsic == intrinsic) {
165 if (index == 0)
166 return intrin;
167 index--;
168 }
169 }
170 }
171 return NULL;
172 }
173
174 nir_deref_instr *
get_deref(nir_deref_type deref_type,unsigned index)175 nir_vars_test::get_deref(nir_deref_type deref_type,
176 unsigned index)
177 {
178 nir_foreach_block(block, b->impl) {
179 nir_foreach_instr(instr, block) {
180 if (instr->type != nir_instr_type_deref)
181 continue;
182 nir_deref_instr *deref = nir_instr_as_deref(instr);
183 if (deref->deref_type == deref_type) {
184 if (index == 0)
185 return deref;
186 index--;
187 }
188 }
189 }
190 return NULL;
191 }
192
193 /* Allow grouping the tests while still sharing the helpers. */
194 class nir_redundant_load_vars_test : public nir_vars_test {};
195 class nir_copy_prop_vars_test : public nir_vars_test {};
196 class nir_dead_write_vars_test : public nir_vars_test {};
197 class nir_combine_stores_test : public nir_vars_test {};
198 class nir_split_vars_test : public nir_vars_test {};
199 class nir_remove_dead_variables_test : public nir_vars_test {};
200
201 } // namespace
202
203 static nir_ssa_def *
nir_load_var_volatile(nir_builder * b,nir_variable * var)204 nir_load_var_volatile(nir_builder *b, nir_variable *var)
205 {
206 return nir_load_deref_with_access(b, nir_build_deref_var(b, var),
207 ACCESS_VOLATILE);
208 }
209
210 static void
nir_store_var_volatile(nir_builder * b,nir_variable * var,nir_ssa_def * value,nir_component_mask_t writemask)211 nir_store_var_volatile(nir_builder *b, nir_variable *var,
212 nir_ssa_def *value, nir_component_mask_t writemask)
213 {
214 nir_store_deref_with_access(b, nir_build_deref_var(b, var),
215 value, writemask, ACCESS_VOLATILE);
216 }
217
TEST_F(nir_redundant_load_vars_test,duplicated_load)218 TEST_F(nir_redundant_load_vars_test, duplicated_load)
219 {
220 /* Load a variable twice in the same block. One should be removed. */
221
222 nir_variable *in = create_int(nir_var_mem_global, "in");
223 nir_variable **out = create_many_int(nir_var_shader_out, "out", 2);
224
225 nir_store_var(b, out[0], nir_load_var(b, in), 1);
226 nir_store_var(b, out[1], nir_load_var(b, in), 1);
227
228 nir_validate_shader(b->shader, NULL);
229
230 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
231
232 bool progress = nir_opt_copy_prop_vars(b->shader);
233 EXPECT_TRUE(progress);
234
235 nir_validate_shader(b->shader, NULL);
236
237 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
238 }
239
TEST_F(nir_redundant_load_vars_test,duplicated_load_volatile)240 TEST_F(nir_redundant_load_vars_test, duplicated_load_volatile)
241 {
242 /* Load a variable twice in the same block. One should be removed. */
243
244 nir_variable *in = create_int(nir_var_mem_global, "in");
245 nir_variable **out = create_many_int(nir_var_shader_out, "out", 3);
246
247 /* Volatile prevents us from eliminating a load by combining it with
248 * another. It shouldn't however, prevent us from combing other
249 * non-volatile loads.
250 */
251 nir_store_var(b, out[0], nir_load_var(b, in), 1);
252 nir_store_var(b, out[1], nir_load_var_volatile(b, in), 1);
253 nir_store_var(b, out[2], nir_load_var(b, in), 1);
254
255 nir_validate_shader(b->shader, NULL);
256
257 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
258
259 bool progress = nir_opt_copy_prop_vars(b->shader);
260 EXPECT_TRUE(progress);
261
262 nir_validate_shader(b->shader, NULL);
263
264 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
265
266 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
267 ASSERT_TRUE(first_store->src[1].is_ssa);
268
269 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2);
270 ASSERT_TRUE(third_store->src[1].is_ssa);
271
272 EXPECT_EQ(first_store->src[1].ssa, third_store->src[1].ssa);
273 }
274
TEST_F(nir_redundant_load_vars_test,duplicated_load_in_two_blocks)275 TEST_F(nir_redundant_load_vars_test, duplicated_load_in_two_blocks)
276 {
277 /* Load a variable twice in different blocks. One should be removed. */
278
279 nir_variable *in = create_int(nir_var_mem_global, "in");
280 nir_variable **out = create_many_int(nir_var_shader_out, "out", 2);
281
282 nir_store_var(b, out[0], nir_load_var(b, in), 1);
283
284 /* Forces the stores to be in different blocks. */
285 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
286
287 nir_store_var(b, out[1], nir_load_var(b, in), 1);
288
289 nir_validate_shader(b->shader, NULL);
290
291 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
292
293 bool progress = nir_opt_copy_prop_vars(b->shader);
294 EXPECT_TRUE(progress);
295
296 nir_validate_shader(b->shader, NULL);
297
298 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
299 }
300
TEST_F(nir_redundant_load_vars_test,invalidate_inside_if_block)301 TEST_F(nir_redundant_load_vars_test, invalidate_inside_if_block)
302 {
303 /* Load variables, then write to some of then in different branches of the
304 * if statement. They should be invalidated accordingly.
305 */
306
307 nir_variable **g = create_many_int(nir_var_shader_temp, "g", 3);
308 nir_variable **out = create_many_int(nir_var_shader_out, "out", 3);
309
310 nir_load_var(b, g[0]);
311 nir_load_var(b, g[1]);
312 nir_load_var(b, g[2]);
313
314 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
315 nir_store_var(b, g[0], nir_imm_int(b, 10), 1);
316
317 nir_push_else(b, if_stmt);
318 nir_store_var(b, g[1], nir_imm_int(b, 20), 1);
319
320 nir_pop_if(b, if_stmt);
321
322 nir_store_var(b, out[0], nir_load_var(b, g[0]), 1);
323 nir_store_var(b, out[1], nir_load_var(b, g[1]), 1);
324 nir_store_var(b, out[2], nir_load_var(b, g[2]), 1);
325
326 nir_validate_shader(b->shader, NULL);
327
328 bool progress = nir_opt_copy_prop_vars(b->shader);
329 EXPECT_TRUE(progress);
330
331 /* There are 3 initial loads, plus 2 loads for the values invalidated
332 * inside the if statement.
333 */
334 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 5);
335
336 /* We only load g[2] once. */
337 unsigned g2_load_count = 0;
338 for (int i = 0; i < 5; i++) {
339 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, i);
340 if (nir_intrinsic_get_var(load, 0) == g[2])
341 g2_load_count++;
342 }
343 EXPECT_EQ(g2_load_count, 1);
344 }
345
TEST_F(nir_redundant_load_vars_test,invalidate_live_load_in_the_end_of_loop)346 TEST_F(nir_redundant_load_vars_test, invalidate_live_load_in_the_end_of_loop)
347 {
348 /* Invalidating a load in the end of loop body will apply to the whole loop
349 * body.
350 */
351
352 nir_variable *v = create_int(nir_var_mem_global, "v");
353
354 nir_load_var(b, v);
355
356 nir_loop *loop = nir_push_loop(b);
357
358 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
359 nir_jump(b, nir_jump_break);
360 nir_pop_if(b, if_stmt);
361
362 nir_load_var(b, v);
363 nir_store_var(b, v, nir_imm_int(b, 10), 1);
364
365 nir_pop_loop(b, loop);
366
367 bool progress = nir_opt_copy_prop_vars(b->shader);
368 ASSERT_FALSE(progress);
369 }
370
TEST_F(nir_copy_prop_vars_test,simple_copies)371 TEST_F(nir_copy_prop_vars_test, simple_copies)
372 {
373 nir_variable *in = create_int(nir_var_shader_in, "in");
374 nir_variable *temp = create_int(nir_var_function_temp, "temp");
375 nir_variable *out = create_int(nir_var_shader_out, "out");
376
377 nir_copy_var(b, temp, in);
378 nir_copy_var(b, out, temp);
379
380 nir_validate_shader(b->shader, NULL);
381
382 bool progress = nir_opt_copy_prop_vars(b->shader);
383 EXPECT_TRUE(progress);
384
385 nir_validate_shader(b->shader, NULL);
386
387 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 2);
388
389 nir_intrinsic_instr *first_copy = get_intrinsic(nir_intrinsic_copy_deref, 0);
390 ASSERT_TRUE(first_copy->src[1].is_ssa);
391
392 nir_intrinsic_instr *second_copy = get_intrinsic(nir_intrinsic_copy_deref, 1);
393 ASSERT_TRUE(second_copy->src[1].is_ssa);
394
395 EXPECT_EQ(first_copy->src[1].ssa, second_copy->src[1].ssa);
396 }
397
TEST_F(nir_copy_prop_vars_test,self_copy)398 TEST_F(nir_copy_prop_vars_test, self_copy)
399 {
400 nir_variable *v = create_int(nir_var_mem_global, "v");
401
402 nir_copy_var(b, v, v);
403
404 nir_validate_shader(b->shader, NULL);
405
406 bool progress = nir_opt_copy_prop_vars(b->shader);
407 EXPECT_TRUE(progress);
408
409 nir_validate_shader(b->shader, NULL);
410
411 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 0);
412 }
413
TEST_F(nir_copy_prop_vars_test,simple_store_load)414 TEST_F(nir_copy_prop_vars_test, simple_store_load)
415 {
416 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
417 unsigned mask = 1 | 2;
418
419 nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20);
420 nir_store_var(b, v[0], stored_value, mask);
421
422 nir_ssa_def *read_value = nir_load_var(b, v[0]);
423 nir_store_var(b, v[1], read_value, mask);
424
425 nir_validate_shader(b->shader, NULL);
426
427 bool progress = nir_opt_copy_prop_vars(b->shader);
428 EXPECT_TRUE(progress);
429
430 nir_validate_shader(b->shader, NULL);
431
432 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
433
434 for (int i = 0; i < 2; i++) {
435 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i);
436 ASSERT_TRUE(store->src[1].is_ssa);
437 EXPECT_EQ(store->src[1].ssa, stored_value);
438 }
439 }
440
TEST_F(nir_copy_prop_vars_test,store_store_load)441 TEST_F(nir_copy_prop_vars_test, store_store_load)
442 {
443 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
444 unsigned mask = 1 | 2;
445
446 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
447 nir_store_var(b, v[0], first_value, mask);
448
449 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
450 nir_store_var(b, v[0], second_value, mask);
451
452 nir_ssa_def *read_value = nir_load_var(b, v[0]);
453 nir_store_var(b, v[1], read_value, mask);
454
455 nir_validate_shader(b->shader, NULL);
456
457 bool progress = nir_opt_copy_prop_vars(b->shader);
458 EXPECT_TRUE(progress);
459
460 nir_validate_shader(b->shader, NULL);
461
462 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
463
464 /* Store to v[1] should use second_value directly. */
465 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2);
466 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
467 ASSERT_TRUE(store_to_v1->src[1].is_ssa);
468 EXPECT_EQ(store_to_v1->src[1].ssa, second_value);
469 }
470
TEST_F(nir_copy_prop_vars_test,store_store_load_different_components)471 TEST_F(nir_copy_prop_vars_test, store_store_load_different_components)
472 {
473 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
474
475 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
476 nir_store_var(b, v[0], first_value, 1 << 1);
477
478 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
479 nir_store_var(b, v[0], second_value, 1 << 0);
480
481 nir_ssa_def *read_value = nir_load_var(b, v[0]);
482 nir_store_var(b, v[1], read_value, 1 << 1);
483
484 nir_validate_shader(b->shader, NULL);
485
486 bool progress = nir_opt_copy_prop_vars(b->shader);
487 EXPECT_TRUE(progress);
488
489 nir_validate_shader(b->shader, NULL);
490
491 nir_opt_constant_folding(b->shader);
492 nir_validate_shader(b->shader, NULL);
493
494 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
495
496 /* Store to v[1] should use first_value directly. The write of
497 * second_value did not overwrite the component it uses.
498 */
499 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2);
500 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
501 ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20);
502 }
503
TEST_F(nir_copy_prop_vars_test,store_store_load_different_components_in_many_blocks)504 TEST_F(nir_copy_prop_vars_test, store_store_load_different_components_in_many_blocks)
505 {
506 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
507
508 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
509 nir_store_var(b, v[0], first_value, 1 << 1);
510
511 /* Adding an if statement will cause blocks to be created. */
512 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
513
514 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
515 nir_store_var(b, v[0], second_value, 1 << 0);
516
517 /* Adding an if statement will cause blocks to be created. */
518 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
519
520 nir_ssa_def *read_value = nir_load_var(b, v[0]);
521 nir_store_var(b, v[1], read_value, 1 << 1);
522
523 nir_validate_shader(b->shader, NULL);
524
525 bool progress = nir_opt_copy_prop_vars(b->shader);
526 EXPECT_TRUE(progress);
527
528 nir_validate_shader(b->shader, NULL);
529
530 nir_opt_constant_folding(b->shader);
531 nir_validate_shader(b->shader, NULL);
532
533 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
534
535 /* Store to v[1] should use first_value directly. The write of
536 * second_value did not overwrite the component it uses.
537 */
538 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2);
539 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
540 ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20);
541 }
542
TEST_F(nir_copy_prop_vars_test,store_volatile)543 TEST_F(nir_copy_prop_vars_test, store_volatile)
544 {
545 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
546 unsigned mask = 1 | 2;
547
548 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
549 nir_store_var(b, v[0], first_value, mask);
550
551 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
552 nir_store_var_volatile(b, v[0], second_value, mask);
553
554 nir_ssa_def *third_value = nir_imm_ivec2(b, 50, 60);
555 nir_store_var(b, v[0], third_value, mask);
556
557 nir_ssa_def *read_value = nir_load_var(b, v[0]);
558 nir_store_var(b, v[1], read_value, mask);
559
560 nir_validate_shader(b->shader, NULL);
561
562 bool progress = nir_opt_copy_prop_vars(b->shader);
563 EXPECT_TRUE(progress);
564
565 nir_validate_shader(b->shader, NULL);
566
567 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4);
568
569 /* Our approach here is a bit scorched-earth. We expect the volatile store
570 * in the middle to cause both that store and the one before it to be kept.
571 * Technically, volatile only prevents combining the volatile store with
572 * another store and one could argue that the store before the volatile and
573 * the one after it could be combined. However, it seems safer to just
574 * treat a volatile store like an atomic and prevent any combining across
575 * it.
576 */
577 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 3);
578 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
579 ASSERT_TRUE(store_to_v1->src[1].is_ssa);
580 EXPECT_EQ(store_to_v1->src[1].ssa, third_value);
581 }
582
TEST_F(nir_copy_prop_vars_test,self_copy_volatile)583 TEST_F(nir_copy_prop_vars_test, self_copy_volatile)
584 {
585 nir_variable *v = create_int(nir_var_mem_global, "v");
586
587 nir_copy_var(b, v, v);
588 nir_copy_deref_with_access(b, nir_build_deref_var(b, v),
589 nir_build_deref_var(b, v),
590 (gl_access_qualifier)0, ACCESS_VOLATILE);
591 nir_copy_deref_with_access(b, nir_build_deref_var(b, v),
592 nir_build_deref_var(b, v),
593 ACCESS_VOLATILE, (gl_access_qualifier)0);
594 nir_copy_var(b, v, v);
595
596 nir_validate_shader(b->shader, NULL);
597
598 bool progress = nir_opt_copy_prop_vars(b->shader);
599 EXPECT_TRUE(progress);
600
601 nir_validate_shader(b->shader, NULL);
602
603 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 2);
604
605 /* Store to v[1] should use second_value directly. */
606 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_copy_deref, 0);
607 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_copy_deref, 1);
608 ASSERT_EQ(nir_intrinsic_src_access(first), ACCESS_VOLATILE);
609 ASSERT_EQ(nir_intrinsic_dst_access(first), (gl_access_qualifier)0);
610 ASSERT_EQ(nir_intrinsic_src_access(second), (gl_access_qualifier)0);
611 ASSERT_EQ(nir_intrinsic_dst_access(second), ACCESS_VOLATILE);
612 }
613
TEST_F(nir_copy_prop_vars_test,memory_barrier_in_two_blocks)614 TEST_F(nir_copy_prop_vars_test, memory_barrier_in_two_blocks)
615 {
616 nir_variable **v = create_many_int(nir_var_mem_global, "v", 4);
617
618 nir_store_var(b, v[0], nir_imm_int(b, 1), 1);
619 nir_store_var(b, v[1], nir_imm_int(b, 2), 1);
620
621 /* Split into many blocks. */
622 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
623
624 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1);
625
626 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQ_REL,
627 nir_var_mem_global);
628
629 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1);
630
631 bool progress = nir_opt_copy_prop_vars(b->shader);
632 ASSERT_TRUE(progress);
633
634 /* Only the second load will remain after the optimization. */
635 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref));
636 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0);
637 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[1]);
638 }
639
TEST_F(nir_redundant_load_vars_test,acquire_barrier_prevents_load_removal)640 TEST_F(nir_redundant_load_vars_test, acquire_barrier_prevents_load_removal)
641 {
642 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1);
643
644 nir_load_var(b, x[0]);
645
646 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
647 nir_var_mem_global);
648
649 nir_load_var(b, x[0]);
650
651 bool progress = nir_opt_copy_prop_vars(b->shader);
652 ASSERT_FALSE(progress);
653
654 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref));
655 }
656
TEST_F(nir_redundant_load_vars_test,acquire_barrier_prevents_same_mode_load_removal)657 TEST_F(nir_redundant_load_vars_test, acquire_barrier_prevents_same_mode_load_removal)
658 {
659 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
660
661 nir_load_var(b, x[0]);
662 nir_load_var(b, x[1]);
663
664 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
665 nir_var_mem_global);
666
667 nir_load_var(b, x[0]);
668 nir_load_var(b, x[1]);
669
670 bool progress = nir_opt_copy_prop_vars(b->shader);
671 ASSERT_FALSE(progress);
672
673 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_load_deref));
674 }
675
TEST_F(nir_redundant_load_vars_test,acquire_barrier_allows_different_mode_load_removal)676 TEST_F(nir_redundant_load_vars_test, acquire_barrier_allows_different_mode_load_removal)
677 {
678 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
679 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2);
680
681 nir_load_var(b, x[0]);
682 nir_load_var(b, x[1]);
683 nir_load_var(b, y[0]);
684 nir_load_var(b, y[1]);
685
686 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
687 nir_var_mem_global);
688
689 nir_load_var(b, x[0]);
690 nir_load_var(b, x[1]);
691 nir_load_var(b, y[0]);
692 nir_load_var(b, y[1]);
693
694 bool progress = nir_opt_copy_prop_vars(b->shader);
695 ASSERT_TRUE(progress);
696
697 ASSERT_EQ(6, count_intrinsics(nir_intrinsic_load_deref));
698
699 nir_intrinsic_instr *load;
700
701 load = get_intrinsic(nir_intrinsic_load_deref, 0);
702 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]);
703 load = get_intrinsic(nir_intrinsic_load_deref, 1);
704 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]);
705
706 load = get_intrinsic(nir_intrinsic_load_deref, 2);
707 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[0]);
708 load = get_intrinsic(nir_intrinsic_load_deref, 3);
709 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[1]);
710
711 load = get_intrinsic(nir_intrinsic_load_deref, 4);
712 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]);
713 load = get_intrinsic(nir_intrinsic_load_deref, 5);
714 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]);
715 }
716
TEST_F(nir_redundant_load_vars_test,release_barrier_allows_load_removal)717 TEST_F(nir_redundant_load_vars_test, release_barrier_allows_load_removal)
718 {
719 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1);
720
721 nir_load_var(b, x[0]);
722
723 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
724 nir_var_mem_global);
725
726 nir_load_var(b, x[0]);
727
728 bool progress = nir_opt_copy_prop_vars(b->shader);
729 ASSERT_TRUE(progress);
730
731 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref));
732 }
733
TEST_F(nir_redundant_load_vars_test,release_barrier_allows_same_mode_load_removal)734 TEST_F(nir_redundant_load_vars_test, release_barrier_allows_same_mode_load_removal)
735 {
736 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
737
738 nir_load_var(b, x[0]);
739 nir_load_var(b, x[1]);
740
741 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
742 nir_var_mem_global);
743
744 nir_load_var(b, x[0]);
745 nir_load_var(b, x[1]);
746
747 bool progress = nir_opt_copy_prop_vars(b->shader);
748 ASSERT_TRUE(progress);
749
750 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref));
751 }
752
TEST_F(nir_redundant_load_vars_test,release_barrier_allows_different_mode_load_removal)753 TEST_F(nir_redundant_load_vars_test, release_barrier_allows_different_mode_load_removal)
754 {
755 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
756 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2);
757
758 nir_load_var(b, x[0]);
759 nir_load_var(b, x[1]);
760 nir_load_var(b, y[0]);
761 nir_load_var(b, y[1]);
762
763 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
764 nir_var_mem_global);
765
766 nir_load_var(b, x[0]);
767 nir_load_var(b, x[1]);
768 nir_load_var(b, y[0]);
769 nir_load_var(b, y[1]);
770
771 bool progress = nir_opt_copy_prop_vars(b->shader);
772 ASSERT_TRUE(progress);
773
774 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_load_deref));
775
776 nir_intrinsic_instr *load;
777
778 load = get_intrinsic(nir_intrinsic_load_deref, 0);
779 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]);
780 load = get_intrinsic(nir_intrinsic_load_deref, 1);
781 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]);
782
783 load = get_intrinsic(nir_intrinsic_load_deref, 2);
784 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[0]);
785 load = get_intrinsic(nir_intrinsic_load_deref, 3);
786 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[1]);
787 }
788
TEST_F(nir_copy_prop_vars_test,acquire_barrier_prevents_propagation)789 TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation)
790 {
791 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1);
792
793 nir_store_var(b, x[0], nir_imm_int(b, 10), 1);
794
795 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
796 nir_var_mem_global);
797
798 nir_load_var(b, x[0]);
799
800 bool progress = nir_opt_copy_prop_vars(b->shader);
801 ASSERT_FALSE(progress);
802
803 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
804 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref));
805 }
806
TEST_F(nir_copy_prop_vars_test,acquire_barrier_prevents_same_mode_propagation)807 TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_same_mode_propagation)
808 {
809 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
810
811 nir_store_var(b, x[0], nir_imm_int(b, 10), 1);
812 nir_store_var(b, x[1], nir_imm_int(b, 20), 1);
813
814 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
815 nir_var_mem_global);
816
817 nir_load_var(b, x[0]);
818 nir_load_var(b, x[1]);
819
820 bool progress = nir_opt_copy_prop_vars(b->shader);
821 ASSERT_FALSE(progress);
822
823 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_store_deref));
824 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref));
825 }
826
TEST_F(nir_copy_prop_vars_test,acquire_barrier_allows_different_mode_propagation)827 TEST_F(nir_copy_prop_vars_test, acquire_barrier_allows_different_mode_propagation)
828 {
829 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
830 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2);
831
832 nir_store_var(b, x[0], nir_imm_int(b, 10), 1);
833 nir_store_var(b, x[1], nir_imm_int(b, 20), 1);
834 nir_store_var(b, y[0], nir_imm_int(b, 30), 1);
835 nir_store_var(b, y[1], nir_imm_int(b, 40), 1);
836
837 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
838 nir_var_mem_global);
839
840 nir_load_var(b, x[0]);
841 nir_load_var(b, x[1]);
842 nir_load_var(b, y[0]);
843 nir_load_var(b, y[1]);
844
845 bool progress = nir_opt_copy_prop_vars(b->shader);
846 ASSERT_TRUE(progress);
847
848 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_store_deref));
849 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref));
850
851 nir_intrinsic_instr *store;
852
853 store = get_intrinsic(nir_intrinsic_store_deref, 0);
854 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[0]);
855 store = get_intrinsic(nir_intrinsic_store_deref, 1);
856 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[1]);
857
858 store = get_intrinsic(nir_intrinsic_store_deref, 2);
859 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[0]);
860 store = get_intrinsic(nir_intrinsic_store_deref, 3);
861 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[1]);
862
863 nir_intrinsic_instr *load;
864
865 load = get_intrinsic(nir_intrinsic_load_deref, 0);
866 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]);
867 load = get_intrinsic(nir_intrinsic_load_deref, 1);
868 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]);
869 }
870
TEST_F(nir_copy_prop_vars_test,release_barrier_allows_propagation)871 TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation)
872 {
873 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1);
874
875 nir_store_var(b, x[0], nir_imm_int(b, 10), 1);
876
877 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
878 nir_var_mem_global);
879
880 nir_load_var(b, x[0]);
881
882 bool progress = nir_opt_copy_prop_vars(b->shader);
883 ASSERT_TRUE(progress);
884
885 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
886 }
887
TEST_F(nir_copy_prop_vars_test,release_barrier_allows_same_mode_propagation)888 TEST_F(nir_copy_prop_vars_test, release_barrier_allows_same_mode_propagation)
889 {
890 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
891
892 nir_store_var(b, x[0], nir_imm_int(b, 10), 1);
893 nir_store_var(b, x[1], nir_imm_int(b, 20), 1);
894
895 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
896 nir_var_mem_global);
897
898 nir_load_var(b, x[0]);
899 nir_load_var(b, x[1]);
900
901 bool progress = nir_opt_copy_prop_vars(b->shader);
902 ASSERT_TRUE(progress);
903
904 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_store_deref));
905 ASSERT_EQ(0, count_intrinsics(nir_intrinsic_load_deref));
906 }
907
TEST_F(nir_copy_prop_vars_test,release_barrier_allows_different_mode_propagation)908 TEST_F(nir_copy_prop_vars_test, release_barrier_allows_different_mode_propagation)
909 {
910 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
911 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2);
912
913 nir_store_var(b, x[0], nir_imm_int(b, 10), 1);
914 nir_store_var(b, x[1], nir_imm_int(b, 20), 1);
915 nir_store_var(b, y[0], nir_imm_int(b, 30), 1);
916 nir_store_var(b, y[1], nir_imm_int(b, 40), 1);
917
918 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
919 nir_var_mem_global);
920
921 nir_load_var(b, x[0]);
922 nir_load_var(b, x[1]);
923 nir_load_var(b, y[0]);
924 nir_load_var(b, y[1]);
925
926 bool progress = nir_opt_copy_prop_vars(b->shader);
927 ASSERT_TRUE(progress);
928
929 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_store_deref));
930 ASSERT_EQ(0, count_intrinsics(nir_intrinsic_load_deref));
931
932 nir_intrinsic_instr *store;
933
934 store = get_intrinsic(nir_intrinsic_store_deref, 0);
935 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[0]);
936 store = get_intrinsic(nir_intrinsic_store_deref, 1);
937 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[1]);
938
939 store = get_intrinsic(nir_intrinsic_store_deref, 2);
940 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[0]);
941 store = get_intrinsic(nir_intrinsic_store_deref, 3);
942 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[1]);
943 }
944
TEST_F(nir_copy_prop_vars_test,acquire_barrier_prevents_propagation_from_copy)945 TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation_from_copy)
946 {
947 nir_variable **x = create_many_int(nir_var_mem_global, "x", 3);
948
949 nir_copy_var(b, x[1], x[0]);
950
951 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
952 nir_var_mem_global);
953
954 nir_copy_var(b, x[2], x[1]);
955
956 bool progress = nir_opt_copy_prop_vars(b->shader);
957 ASSERT_FALSE(progress);
958
959 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref));
960
961 nir_intrinsic_instr *copy;
962
963 copy = get_intrinsic(nir_intrinsic_copy_deref, 0);
964 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]);
965
966 copy = get_intrinsic(nir_intrinsic_copy_deref, 1);
967 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[1]);
968 }
969
TEST_F(nir_copy_prop_vars_test,acquire_barrier_prevents_propagation_from_copy_to_different_mode)970 TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation_from_copy_to_different_mode)
971 {
972 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
973 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 1);
974
975 nir_copy_var(b, y[0], x[0]);
976
977 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE,
978 nir_var_mem_global);
979
980 nir_copy_var(b, x[1], y[0]);
981
982 bool progress = nir_opt_copy_prop_vars(b->shader);
983 ASSERT_FALSE(progress);
984
985 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref));
986
987 nir_intrinsic_instr *copy;
988
989 copy = get_intrinsic(nir_intrinsic_copy_deref, 0);
990 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]);
991
992 copy = get_intrinsic(nir_intrinsic_copy_deref, 1);
993 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), y[0]);
994 }
995
TEST_F(nir_copy_prop_vars_test,release_barrier_allows_propagation_from_copy)996 TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation_from_copy)
997 {
998 nir_variable **x = create_many_int(nir_var_mem_global, "x", 3);
999
1000 nir_copy_var(b, x[1], x[0]);
1001
1002 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
1003 nir_var_mem_global);
1004
1005 nir_copy_var(b, x[2], x[1]);
1006
1007 bool progress = nir_opt_copy_prop_vars(b->shader);
1008 ASSERT_TRUE(progress);
1009
1010 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref));
1011
1012 nir_intrinsic_instr *copy;
1013
1014 copy = get_intrinsic(nir_intrinsic_copy_deref, 0);
1015 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]);
1016
1017 copy = get_intrinsic(nir_intrinsic_copy_deref, 1);
1018 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]);
1019 }
1020
TEST_F(nir_copy_prop_vars_test,release_barrier_allows_propagation_from_copy_to_different_mode)1021 TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation_from_copy_to_different_mode)
1022 {
1023 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2);
1024 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 1);
1025
1026 nir_copy_var(b, y[0], x[0]);
1027
1028 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE,
1029 nir_var_mem_global);
1030
1031 nir_copy_var(b, x[1], y[0]);
1032
1033 bool progress = nir_opt_copy_prop_vars(b->shader);
1034 ASSERT_TRUE(progress);
1035
1036 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref));
1037
1038 nir_intrinsic_instr *copy;
1039
1040 copy = get_intrinsic(nir_intrinsic_copy_deref, 0);
1041 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]);
1042
1043 copy = get_intrinsic(nir_intrinsic_copy_deref, 1);
1044 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]);
1045 }
1046
TEST_F(nir_copy_prop_vars_test,simple_store_load_in_two_blocks)1047 TEST_F(nir_copy_prop_vars_test, simple_store_load_in_two_blocks)
1048 {
1049 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
1050 unsigned mask = 1 | 2;
1051
1052 nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20);
1053 nir_store_var(b, v[0], stored_value, mask);
1054
1055 /* Adding an if statement will cause blocks to be created. */
1056 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1057
1058 nir_ssa_def *read_value = nir_load_var(b, v[0]);
1059 nir_store_var(b, v[1], read_value, mask);
1060
1061 nir_validate_shader(b->shader, NULL);
1062
1063 bool progress = nir_opt_copy_prop_vars(b->shader);
1064 EXPECT_TRUE(progress);
1065
1066 nir_validate_shader(b->shader, NULL);
1067
1068 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1069
1070 for (int i = 0; i < 2; i++) {
1071 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i);
1072 ASSERT_TRUE(store->src[1].is_ssa);
1073 EXPECT_EQ(store->src[1].ssa, stored_value);
1074 }
1075 }
1076
TEST_F(nir_copy_prop_vars_test,load_direct_array_deref_on_vector_reuses_previous_load)1077 TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_load)
1078 {
1079 nir_variable *in0 = create_ivec2(nir_var_mem_global, "in0");
1080 nir_variable *in1 = create_ivec2(nir_var_mem_global, "in1");
1081 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec");
1082 nir_variable *out = create_int(nir_var_mem_global, "out");
1083
1084 nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0);
1085 nir_store_var(b, vec, nir_load_var(b, in1), 1 << 1);
1086
1087 /* This load will be dropped, as vec.y (or vec[1]) is already known. */
1088 nir_deref_instr *deref =
1089 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
1090 nir_ssa_def *loaded_from_deref = nir_load_deref(b, deref);
1091
1092 /* This store should use the value loaded from in1. */
1093 nir_store_var(b, out, loaded_from_deref, 1 << 0);
1094
1095 nir_validate_shader(b->shader, NULL);
1096 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
1097 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1098
1099 bool progress = nir_opt_copy_prop_vars(b->shader);
1100 EXPECT_TRUE(progress);
1101
1102 nir_validate_shader(b->shader, NULL);
1103 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
1104 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1105
1106 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 2);
1107 ASSERT_TRUE(store->src[1].is_ssa);
1108
1109 /* NOTE: The ALU instruction is how we get the vec.y. */
1110 ASSERT_TRUE(nir_src_as_alu_instr(store->src[1]));
1111 }
1112
TEST_F(nir_copy_prop_vars_test,load_direct_array_deref_on_vector_reuses_previous_copy)1113 TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_copy)
1114 {
1115 nir_variable *in0 = create_ivec2(nir_var_mem_global, "in0");
1116 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec");
1117
1118 nir_copy_var(b, vec, in0);
1119
1120 /* This load will be replaced with one from in0. */
1121 nir_deref_instr *deref =
1122 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
1123 nir_load_deref(b, deref);
1124
1125 nir_validate_shader(b->shader, NULL);
1126
1127 bool progress = nir_opt_copy_prop_vars(b->shader);
1128 EXPECT_TRUE(progress);
1129
1130 nir_validate_shader(b->shader, NULL);
1131 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1132
1133 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0);
1134 ASSERT_EQ(nir_intrinsic_get_var(load, 0), in0);
1135 }
1136
TEST_F(nir_copy_prop_vars_test,load_direct_array_deref_on_vector_gets_reused)1137 TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_gets_reused)
1138 {
1139 nir_variable *in0 = create_ivec2(nir_var_mem_global, "in0");
1140 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec");
1141 nir_variable *out = create_ivec2(nir_var_mem_global, "out");
1142
1143 /* Loading "vec[1]" deref will save the information about vec.y. */
1144 nir_deref_instr *deref =
1145 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
1146 nir_load_deref(b, deref);
1147
1148 /* Store to vec.x. */
1149 nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0);
1150
1151 /* This load will be dropped, since both vec.x and vec.y are known. */
1152 nir_ssa_def *loaded_from_vec = nir_load_var(b, vec);
1153 nir_store_var(b, out, loaded_from_vec, 0x3);
1154
1155 nir_validate_shader(b->shader, NULL);
1156 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
1157 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1158
1159 bool progress = nir_opt_copy_prop_vars(b->shader);
1160 EXPECT_TRUE(progress);
1161
1162 nir_validate_shader(b->shader, NULL);
1163 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
1164 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1165
1166 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 1);
1167 ASSERT_TRUE(store->src[1].is_ssa);
1168 ASSERT_TRUE(nir_src_as_alu_instr(store->src[1]));
1169 }
1170
TEST_F(nir_copy_prop_vars_test,store_load_direct_array_deref_on_vector)1171 TEST_F(nir_copy_prop_vars_test, store_load_direct_array_deref_on_vector)
1172 {
1173 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec");
1174 nir_variable *out0 = create_int(nir_var_mem_global, "out0");
1175 nir_variable *out1 = create_ivec2(nir_var_mem_global, "out1");
1176
1177 /* Store to "vec[1]" and "vec[0]". */
1178 nir_deref_instr *store_deref_y =
1179 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
1180 nir_store_deref(b, store_deref_y, nir_imm_int(b, 20), 1);
1181
1182 nir_deref_instr *store_deref_x =
1183 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 0);
1184 nir_store_deref(b, store_deref_x, nir_imm_int(b, 10), 1);
1185
1186 /* Both loads below will be dropped, because the values are already known. */
1187 nir_deref_instr *load_deref_y =
1188 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
1189 nir_store_var(b, out0, nir_load_deref(b, load_deref_y), 1);
1190
1191 nir_store_var(b, out1, nir_load_var(b, vec), 1);
1192
1193 nir_validate_shader(b->shader, NULL);
1194 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
1195 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4);
1196
1197 bool progress = nir_opt_copy_prop_vars(b->shader);
1198 EXPECT_TRUE(progress);
1199
1200 nir_validate_shader(b->shader, NULL);
1201 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0);
1202 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4);
1203
1204 /* Third store will just use the value from first store. */
1205 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
1206 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2);
1207 ASSERT_TRUE(third_store->src[1].is_ssa);
1208 EXPECT_EQ(third_store->src[1].ssa, first_store->src[1].ssa);
1209
1210 /* Fourth store will compose first and second store values. */
1211 nir_intrinsic_instr *fourth_store = get_intrinsic(nir_intrinsic_store_deref, 3);
1212 ASSERT_TRUE(fourth_store->src[1].is_ssa);
1213 EXPECT_TRUE(nir_src_as_alu_instr(fourth_store->src[1]));
1214 }
1215
TEST_F(nir_copy_prop_vars_test,store_load_indirect_array_deref_on_vector)1216 TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref_on_vector)
1217 {
1218 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec");
1219 nir_variable *idx = create_int(nir_var_mem_global, "idx");
1220 nir_variable *out = create_int(nir_var_mem_global, "out");
1221
1222 nir_ssa_def *idx_ssa = nir_load_var(b, idx);
1223
1224 /* Store to vec[idx]. */
1225 nir_deref_instr *store_deref =
1226 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa);
1227 nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1);
1228
1229 /* Load from vec[idx] to store in out. This load should be dropped. */
1230 nir_deref_instr *load_deref =
1231 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa);
1232 nir_store_var(b, out, nir_load_deref(b, load_deref), 1);
1233
1234 nir_validate_shader(b->shader, NULL);
1235 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
1236 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1237
1238 bool progress = nir_opt_copy_prop_vars(b->shader);
1239 EXPECT_TRUE(progress);
1240
1241 nir_validate_shader(b->shader, NULL);
1242 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1243 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1244
1245 /* Store to vec[idx] propagated to out. */
1246 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
1247 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
1248 ASSERT_TRUE(first->src[1].is_ssa);
1249 ASSERT_TRUE(second->src[1].is_ssa);
1250 EXPECT_EQ(first->src[1].ssa, second->src[1].ssa);
1251 }
1252
TEST_F(nir_copy_prop_vars_test,store_load_direct_and_indirect_array_deref_on_vector)1253 TEST_F(nir_copy_prop_vars_test, store_load_direct_and_indirect_array_deref_on_vector)
1254 {
1255 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec");
1256 nir_variable *idx = create_int(nir_var_mem_global, "idx");
1257 nir_variable **out = create_many_int(nir_var_mem_global, "out", 2);
1258
1259 nir_ssa_def *idx_ssa = nir_load_var(b, idx);
1260
1261 /* Store to vec. */
1262 nir_store_var(b, vec, nir_imm_ivec2(b, 10, 10), 1 | 2);
1263
1264 /* Load from vec[idx]. This load is currently not dropped. */
1265 nir_deref_instr *indirect =
1266 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa);
1267 nir_store_var(b, out[0], nir_load_deref(b, indirect), 1);
1268
1269 /* Load from vec[idx] again. This load should be dropped. */
1270 nir_store_var(b, out[1], nir_load_deref(b, indirect), 1);
1271
1272 nir_validate_shader(b->shader, NULL);
1273 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
1274 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1275
1276 bool progress = nir_opt_copy_prop_vars(b->shader);
1277 EXPECT_TRUE(progress);
1278
1279 nir_validate_shader(b->shader, NULL);
1280 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
1281 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1282
1283 /* Store to vec[idx] propagated to out. */
1284 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
1285 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
1286 ASSERT_TRUE(second->src[1].is_ssa);
1287 ASSERT_TRUE(third->src[1].is_ssa);
1288 EXPECT_EQ(second->src[1].ssa, third->src[1].ssa);
1289 }
1290
TEST_F(nir_copy_prop_vars_test,store_load_indirect_array_deref)1291 TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref)
1292 {
1293 nir_variable *arr = create_var(nir_var_mem_global,
1294 glsl_array_type(glsl_int_type(), 10, 0),
1295 "arr");
1296 nir_variable *idx = create_int(nir_var_mem_global, "idx");
1297 nir_variable *out = create_int(nir_var_mem_global, "out");
1298
1299 nir_ssa_def *idx_ssa = nir_load_var(b, idx);
1300
1301 /* Store to arr[idx]. */
1302 nir_deref_instr *store_deref =
1303 nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa);
1304 nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1);
1305
1306 /* Load from arr[idx] to store in out. This load should be dropped. */
1307 nir_deref_instr *load_deref =
1308 nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa);
1309 nir_store_var(b, out, nir_load_deref(b, load_deref), 1);
1310
1311 nir_validate_shader(b->shader, NULL);
1312 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
1313 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1314
1315 bool progress = nir_opt_copy_prop_vars(b->shader);
1316 EXPECT_TRUE(progress);
1317
1318 nir_validate_shader(b->shader, NULL);
1319 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1320 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
1321
1322 /* Store to arr[idx] propagated to out. */
1323 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
1324 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
1325 ASSERT_TRUE(first->src[1].is_ssa);
1326 ASSERT_TRUE(second->src[1].is_ssa);
1327 EXPECT_EQ(first->src[1].ssa, second->src[1].ssa);
1328 }
1329
TEST_F(nir_copy_prop_vars_test,restrict_ssbo_bindings)1330 TEST_F(nir_copy_prop_vars_test, restrict_ssbo_bindings)
1331 {
1332 glsl_struct_field field = glsl_struct_field();
1333 field.type = glsl_int_type();
1334 field.name = "x";
1335 const glsl_type *ifc_type =
1336 glsl_type::get_interface_instance(&field, 1,
1337 GLSL_INTERFACE_PACKING_STD430,
1338 false /* row_major */, "b");
1339 nir_variable *ssbo0 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo0");
1340 nir_variable *ssbo1 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo1");
1341 ssbo0->data.access = ssbo1->data.access = ACCESS_RESTRICT;
1342 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
1343 out->data.access = ACCESS_RESTRICT;
1344
1345 nir_deref_instr *ssbo0_x =
1346 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo0), 0);
1347 nir_store_deref(b, ssbo0_x, nir_imm_int(b, 20), 1);
1348
1349 nir_deref_instr *ssbo1_x =
1350 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo1), 0);
1351 nir_store_deref(b, ssbo1_x, nir_imm_int(b, 30), 1);
1352
1353 /* Load ssbo0.x and store it in out.x. This load should be dropped */
1354 nir_deref_instr *out_x =
1355 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
1356 nir_store_deref(b, out_x, nir_load_deref(b, ssbo0_x), 1);
1357
1358 nir_validate_shader(b->shader, NULL);
1359 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1360 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1361
1362 bool progress = nir_opt_copy_prop_vars(b->shader);
1363 EXPECT_TRUE(progress);
1364
1365 nir_validate_shader(b->shader, NULL);
1366 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0);
1367 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1368
1369 /* Store to b0.x propagated to out. */
1370 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
1371 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
1372 ASSERT_TRUE(first->src[1].is_ssa);
1373 ASSERT_TRUE(third->src[1].is_ssa);
1374 EXPECT_EQ(first->src[1].ssa, third->src[1].ssa);
1375 }
1376
TEST_F(nir_copy_prop_vars_test,aliasing_ssbo_bindings)1377 TEST_F(nir_copy_prop_vars_test, aliasing_ssbo_bindings)
1378 {
1379 glsl_struct_field field = glsl_struct_field();
1380 field.type = glsl_int_type();
1381 field.name = "x";
1382 const glsl_type *ifc_type =
1383 glsl_type::get_interface_instance(&field, 1,
1384 GLSL_INTERFACE_PACKING_STD430,
1385 false /* row_major */, "b");
1386 nir_variable *ssbo0 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo0");
1387 nir_variable *ssbo1 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo1");
1388 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
1389 out->data.access = ACCESS_RESTRICT;
1390
1391 nir_deref_instr *ssbo0_x =
1392 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo0), 0);
1393 nir_store_deref(b, ssbo0_x, nir_imm_int(b, 20), 1);
1394
1395 nir_deref_instr *ssbo1_x =
1396 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo1), 0);
1397 nir_store_deref(b, ssbo1_x, nir_imm_int(b, 30), 1);
1398
1399 /* Load ssbo0.x and store it in out.x. This load should not be dropped */
1400 nir_deref_instr *out_x =
1401 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
1402 nir_store_deref(b, out_x, nir_load_deref(b, ssbo0_x), 1);
1403
1404 nir_validate_shader(b->shader, NULL);
1405 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1406 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1407
1408 bool progress = nir_opt_copy_prop_vars(b->shader);
1409 EXPECT_FALSE(progress);
1410
1411 nir_validate_shader(b->shader, NULL);
1412 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1413 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1414 }
1415
TEST_F(nir_copy_prop_vars_test,ssbo_array_binding_indirect)1416 TEST_F(nir_copy_prop_vars_test, ssbo_array_binding_indirect)
1417 {
1418 glsl_struct_field field = glsl_struct_field();
1419 field.type = glsl_int_type();
1420 field.name = "x";
1421 const glsl_type *ifc_type =
1422 glsl_type::get_interface_instance(&field, 1,
1423 GLSL_INTERFACE_PACKING_STD430,
1424 false /* row_major */, "b");
1425 const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2);
1426 nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type,
1427 "ssbo_arr");
1428 ssbo_arr->data.access = ACCESS_RESTRICT;
1429 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
1430 out->data.access = ACCESS_RESTRICT;
1431
1432 nir_deref_instr *ssbo_0 =
1433 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0);
1434 nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0);
1435 nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1);
1436
1437 nir_deref_instr *ssbo_i =
1438 nir_build_deref_array(b, nir_build_deref_var(b, ssbo_arr),
1439 nir_load_local_invocation_index(b));
1440 nir_deref_instr *ssbo_i_x = nir_build_deref_struct(b, ssbo_i, 0);
1441 nir_store_deref(b, ssbo_i_x, nir_imm_int(b, 30), 1);
1442
1443 /* Load ssbo_arr[0].x and store it in out.x. This load should not be dropped */
1444 nir_deref_instr *out_x =
1445 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
1446 nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1);
1447
1448 nir_validate_shader(b->shader, NULL);
1449 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1450 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1451
1452 bool progress = nir_opt_copy_prop_vars(b->shader);
1453 EXPECT_FALSE(progress);
1454
1455 nir_validate_shader(b->shader, NULL);
1456 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1457 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1458 }
1459
TEST_F(nir_copy_prop_vars_test,restrict_ssbo_array_binding)1460 TEST_F(nir_copy_prop_vars_test, restrict_ssbo_array_binding)
1461 {
1462 glsl_struct_field field = glsl_struct_field();
1463 field.type = glsl_int_type();
1464 field.name = "x";
1465 const glsl_type *ifc_type =
1466 glsl_type::get_interface_instance(&field, 1,
1467 GLSL_INTERFACE_PACKING_STD430,
1468 false /* row_major */, "b");
1469 const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2);
1470 nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type,
1471 "ssbo_arr");
1472 ssbo_arr->data.access = ACCESS_RESTRICT;
1473 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
1474 out->data.access = ACCESS_RESTRICT;
1475
1476 nir_deref_instr *ssbo_0 =
1477 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0);
1478 nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0);
1479 nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1);
1480
1481 nir_deref_instr *ssbo_1 =
1482 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 1);
1483 nir_deref_instr *ssbo_1_x = nir_build_deref_struct(b, ssbo_1, 0);
1484 nir_store_deref(b, ssbo_1_x, nir_imm_int(b, 30), 1);
1485
1486 /* Load ssbo_arr[0].x and store it in out.x. This load should be dropped */
1487 nir_deref_instr *out_x =
1488 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
1489 nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1);
1490
1491 nir_validate_shader(b->shader, NULL);
1492 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1493 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1494
1495 bool progress = nir_opt_copy_prop_vars(b->shader);
1496 EXPECT_TRUE(progress);
1497
1498 nir_validate_shader(b->shader, NULL);
1499 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0);
1500 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1501
1502 /* Store to b0.x propagated to out. */
1503 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
1504 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
1505 ASSERT_TRUE(first->src[1].is_ssa);
1506 ASSERT_TRUE(third->src[1].is_ssa);
1507 EXPECT_EQ(first->src[1].ssa, third->src[1].ssa);
1508 }
1509
TEST_F(nir_copy_prop_vars_test,aliasing_ssbo_array_binding)1510 TEST_F(nir_copy_prop_vars_test, aliasing_ssbo_array_binding)
1511 {
1512 glsl_struct_field field = glsl_struct_field();
1513 field.type = glsl_int_type();
1514 field.name = "x";
1515 const glsl_type *ifc_type =
1516 glsl_type::get_interface_instance(&field, 1,
1517 GLSL_INTERFACE_PACKING_STD430,
1518 false /* row_major */, "b");
1519 const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2);
1520 nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type,
1521 "ssbo_arr");
1522 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out");
1523 out->data.access = ACCESS_RESTRICT;
1524
1525 nir_deref_instr *ssbo_0 =
1526 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0);
1527 nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0);
1528 nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1);
1529
1530 nir_deref_instr *ssbo_1 =
1531 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 1);
1532 nir_deref_instr *ssbo_1_x = nir_build_deref_struct(b, ssbo_1, 0);
1533 nir_store_deref(b, ssbo_1_x, nir_imm_int(b, 30), 1);
1534
1535 /* Load ssbo_arr[0].x and store it in out.x. This load should not be dropped */
1536 nir_deref_instr *out_x =
1537 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0);
1538 nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1);
1539
1540 nir_validate_shader(b->shader, NULL);
1541 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1542 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1543
1544 bool progress = nir_opt_copy_prop_vars(b->shader);
1545 EXPECT_FALSE(progress);
1546
1547 nir_validate_shader(b->shader, NULL);
1548 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
1549 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1550 }
1551
TEST_F(nir_dead_write_vars_test,no_dead_writes_in_block)1552 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block)
1553 {
1554 nir_variable **v = create_many_int(nir_var_mem_global, "v", 2);
1555
1556 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1557
1558 bool progress = nir_opt_dead_write_vars(b->shader);
1559 ASSERT_FALSE(progress);
1560 }
1561
TEST_F(nir_dead_write_vars_test,no_dead_writes_different_components_in_block)1562 TEST_F(nir_dead_write_vars_test, no_dead_writes_different_components_in_block)
1563 {
1564 nir_variable **v = create_many_ivec2(nir_var_mem_global, "v", 3);
1565
1566 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
1567 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1 << 1);
1568
1569 bool progress = nir_opt_dead_write_vars(b->shader);
1570 ASSERT_FALSE(progress);
1571 }
1572
TEST_F(nir_dead_write_vars_test,volatile_write)1573 TEST_F(nir_dead_write_vars_test, volatile_write)
1574 {
1575 nir_variable *v = create_int(nir_var_mem_global, "v");
1576
1577 nir_store_var(b, v, nir_imm_int(b, 0), 0x1);
1578 nir_store_var_volatile(b, v, nir_imm_int(b, 1), 0x1);
1579 nir_store_var(b, v, nir_imm_int(b, 2), 0x1);
1580
1581 /* Our approach here is a bit scorched-earth. We expect the volatile store
1582 * in the middle to cause both that store and the one before it to be kept.
1583 * Technically, volatile only prevents combining the volatile store with
1584 * another store and one could argue that the store before the volatile and
1585 * the one after it could be combined. However, it seems safer to just
1586 * treat a volatile store like an atomic and prevent any combining across
1587 * it.
1588 */
1589 bool progress = nir_opt_dead_write_vars(b->shader);
1590 ASSERT_FALSE(progress);
1591 }
1592
TEST_F(nir_dead_write_vars_test,volatile_copies)1593 TEST_F(nir_dead_write_vars_test, volatile_copies)
1594 {
1595 nir_variable **v = create_many_int(nir_var_mem_global, "v", 2);
1596
1597 nir_copy_var(b, v[0], v[1]);
1598 nir_copy_deref_with_access(b, nir_build_deref_var(b, v[0]),
1599 nir_build_deref_var(b, v[1]),
1600 ACCESS_VOLATILE, (gl_access_qualifier)0);
1601 nir_copy_var(b, v[0], v[1]);
1602
1603 /* Our approach here is a bit scorched-earth. We expect the volatile store
1604 * in the middle to cause both that store and the one before it to be kept.
1605 * Technically, volatile only prevents combining the volatile store with
1606 * another store and one could argue that the store before the volatile and
1607 * the one after it could be combined. However, it seems safer to just
1608 * treat a volatile store like an atomic and prevent any combining across
1609 * it.
1610 */
1611 bool progress = nir_opt_dead_write_vars(b->shader);
1612 ASSERT_FALSE(progress);
1613 }
1614
TEST_F(nir_dead_write_vars_test,no_dead_writes_in_if_statement)1615 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_if_statement)
1616 {
1617 nir_variable **v = create_many_int(nir_var_mem_global, "v", 6);
1618
1619 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1);
1620 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1);
1621
1622 /* Each arm of the if statement will overwrite one store. */
1623 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
1624 nir_store_var(b, v[2], nir_load_var(b, v[4]), 1);
1625
1626 nir_push_else(b, if_stmt);
1627 nir_store_var(b, v[3], nir_load_var(b, v[5]), 1);
1628
1629 nir_pop_if(b, if_stmt);
1630
1631 bool progress = nir_opt_dead_write_vars(b->shader);
1632 ASSERT_FALSE(progress);
1633 }
1634
TEST_F(nir_dead_write_vars_test,no_dead_writes_in_loop_statement)1635 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_loop_statement)
1636 {
1637 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3);
1638
1639 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1640
1641 /* Loop will write other value. Since it might not be executed, it doesn't
1642 * kill the first write.
1643 */
1644 nir_loop *loop = nir_push_loop(b);
1645
1646 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
1647 nir_jump(b, nir_jump_break);
1648 nir_pop_if(b, if_stmt);
1649
1650 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
1651 nir_pop_loop(b, loop);
1652
1653 bool progress = nir_opt_dead_write_vars(b->shader);
1654 ASSERT_FALSE(progress);
1655 }
1656
TEST_F(nir_dead_write_vars_test,dead_write_in_block)1657 TEST_F(nir_dead_write_vars_test, dead_write_in_block)
1658 {
1659 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3);
1660
1661 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1662 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1663 nir_store_var(b, v[0], load_v2, 1);
1664
1665 bool progress = nir_opt_dead_write_vars(b->shader);
1666 ASSERT_TRUE(progress);
1667
1668 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1669
1670 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1671 ASSERT_TRUE(store->src[1].is_ssa);
1672 EXPECT_EQ(store->src[1].ssa, load_v2);
1673 }
1674
TEST_F(nir_dead_write_vars_test,dead_write_components_in_block)1675 TEST_F(nir_dead_write_vars_test, dead_write_components_in_block)
1676 {
1677 nir_variable **v = create_many_ivec2(nir_var_mem_global, "v", 3);
1678
1679 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
1680 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1681 nir_store_var(b, v[0], load_v2, 1 << 0);
1682
1683 bool progress = nir_opt_dead_write_vars(b->shader);
1684 ASSERT_TRUE(progress);
1685
1686 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1687
1688 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1689 ASSERT_TRUE(store->src[1].is_ssa);
1690 EXPECT_EQ(store->src[1].ssa, load_v2);
1691 }
1692
1693
1694 /* TODO: The DISABLED tests below depend on the dead write removal be able to
1695 * identify dead writes between multiple blocks. This is still not
1696 * implemented.
1697 */
1698
TEST_F(nir_dead_write_vars_test,DISABLED_dead_write_in_two_blocks)1699 TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_in_two_blocks)
1700 {
1701 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3);
1702
1703 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1704 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1705
1706 /* Causes the stores to be in different blocks. */
1707 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1708
1709 nir_store_var(b, v[0], load_v2, 1);
1710
1711 bool progress = nir_opt_dead_write_vars(b->shader);
1712 ASSERT_TRUE(progress);
1713
1714 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1715
1716 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1717 ASSERT_TRUE(store->src[1].is_ssa);
1718 EXPECT_EQ(store->src[1].ssa, load_v2);
1719 }
1720
TEST_F(nir_dead_write_vars_test,DISABLED_dead_write_components_in_two_blocks)1721 TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_components_in_two_blocks)
1722 {
1723 nir_variable **v = create_many_ivec2(nir_var_mem_global, "v", 3);
1724
1725 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
1726
1727 /* Causes the stores to be in different blocks. */
1728 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1729
1730 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1731 nir_store_var(b, v[0], load_v2, 1 << 0);
1732
1733 bool progress = nir_opt_dead_write_vars(b->shader);
1734 ASSERT_TRUE(progress);
1735
1736 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1737
1738 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1739 ASSERT_TRUE(store->src[1].is_ssa);
1740 EXPECT_EQ(store->src[1].ssa, load_v2);
1741 }
1742
TEST_F(nir_dead_write_vars_test,DISABLED_dead_writes_in_if_statement)1743 TEST_F(nir_dead_write_vars_test, DISABLED_dead_writes_in_if_statement)
1744 {
1745 nir_variable **v = create_many_int(nir_var_mem_global, "v", 4);
1746
1747 /* Both branches will overwrite, making the previous store dead. */
1748 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1749
1750 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
1751 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1752 nir_store_var(b, v[0], load_v2, 1);
1753
1754 nir_push_else(b, if_stmt);
1755 nir_ssa_def *load_v3 = nir_load_var(b, v[3]);
1756 nir_store_var(b, v[0], load_v3, 1);
1757
1758 nir_pop_if(b, if_stmt);
1759
1760 bool progress = nir_opt_dead_write_vars(b->shader);
1761 ASSERT_TRUE(progress);
1762 EXPECT_EQ(2, count_intrinsics(nir_intrinsic_store_deref));
1763
1764 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
1765 ASSERT_TRUE(first_store->src[1].is_ssa);
1766 EXPECT_EQ(first_store->src[1].ssa, load_v2);
1767
1768 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1);
1769 ASSERT_TRUE(second_store->src[1].is_ssa);
1770 EXPECT_EQ(second_store->src[1].ssa, load_v3);
1771 }
1772
TEST_F(nir_dead_write_vars_test,DISABLED_memory_barrier_in_two_blocks)1773 TEST_F(nir_dead_write_vars_test, DISABLED_memory_barrier_in_two_blocks)
1774 {
1775 nir_variable **v = create_many_int(nir_var_mem_global, "v", 2);
1776
1777 nir_store_var(b, v[0], nir_imm_int(b, 1), 1);
1778 nir_store_var(b, v[1], nir_imm_int(b, 2), 1);
1779
1780 /* Split into many blocks. */
1781 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1782
1783 /* Because it is before the barrier, this will kill the previous store to that target. */
1784 nir_store_var(b, v[0], nir_imm_int(b, 3), 1);
1785
1786 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQ_REL,
1787 nir_var_mem_global);
1788
1789 nir_store_var(b, v[1], nir_imm_int(b, 4), 1);
1790
1791 bool progress = nir_opt_dead_write_vars(b->shader);
1792 ASSERT_TRUE(progress);
1793
1794 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
1795 }
1796
TEST_F(nir_dead_write_vars_test,DISABLED_unrelated_barrier_in_two_blocks)1797 TEST_F(nir_dead_write_vars_test, DISABLED_unrelated_barrier_in_two_blocks)
1798 {
1799 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3);
1800 nir_variable *out = create_int(nir_var_shader_out, "out");
1801
1802 nir_store_var(b, out, nir_load_var(b, v[1]), 1);
1803 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1804
1805 /* Split into many blocks. */
1806 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1807
1808 /* Emit vertex will ensure writes to output variables are considered used,
1809 * but should not affect other types of variables. */
1810
1811 nir_emit_vertex(b);
1812
1813 nir_store_var(b, out, nir_load_var(b, v[2]), 1);
1814 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
1815
1816 bool progress = nir_opt_dead_write_vars(b->shader);
1817 ASSERT_TRUE(progress);
1818
1819 /* Verify the first write to v[0] was removed. */
1820 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
1821
1822 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
1823 EXPECT_EQ(nir_intrinsic_get_var(first_store, 0), out);
1824
1825 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1);
1826 EXPECT_EQ(nir_intrinsic_get_var(second_store, 0), out);
1827
1828 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2);
1829 EXPECT_EQ(nir_intrinsic_get_var(third_store, 0), v[0]);
1830 }
1831
TEST_F(nir_combine_stores_test,non_overlapping_stores)1832 TEST_F(nir_combine_stores_test, non_overlapping_stores)
1833 {
1834 nir_variable **v = create_many_ivec4(nir_var_mem_global, "v", 4);
1835 nir_variable *out = create_ivec4(nir_var_shader_out, "out");
1836
1837 for (int i = 0; i < 4; i++)
1838 nir_store_var(b, out, nir_load_var(b, v[i]), 1 << i);
1839
1840 nir_validate_shader(b->shader, NULL);
1841
1842 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
1843 ASSERT_TRUE(progress);
1844
1845 nir_validate_shader(b->shader, NULL);
1846
1847 /* Clean up to verify from where the values in combined store are coming. */
1848 nir_copy_prop(b->shader);
1849 nir_opt_dce(b->shader);
1850
1851 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1852 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1853 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1854 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1855
1856 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1857 ASSERT_TRUE(vec);
1858 for (int i = 0; i < 4; i++) {
1859 nir_intrinsic_instr *load = nir_src_as_intrinsic(vec->src[i].src);
1860 ASSERT_EQ(load->intrinsic, nir_intrinsic_load_deref);
1861 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[i])
1862 << "Source value for component " << i << " of store is wrong";
1863 ASSERT_EQ(vec->src[i].swizzle[0], i)
1864 << "Source component for component " << i << " of store is wrong";
1865 }
1866 }
1867
TEST_F(nir_combine_stores_test,overlapping_stores)1868 TEST_F(nir_combine_stores_test, overlapping_stores)
1869 {
1870 nir_variable **v = create_many_ivec4(nir_var_mem_global, "v", 3);
1871 nir_variable *out = create_ivec4(nir_var_shader_out, "out");
1872
1873 /* Make stores with xy, yz and zw masks. */
1874 for (int i = 0; i < 3; i++) {
1875 nir_component_mask_t mask = (1 << i) | (1 << (i + 1));
1876 nir_store_var(b, out, nir_load_var(b, v[i]), mask);
1877 }
1878
1879 nir_validate_shader(b->shader, NULL);
1880
1881 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
1882 ASSERT_TRUE(progress);
1883
1884 nir_validate_shader(b->shader, NULL);
1885
1886 /* Clean up to verify from where the values in combined store are coming. */
1887 nir_copy_prop(b->shader);
1888 nir_opt_dce(b->shader);
1889
1890 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1891 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1892 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1893 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1894
1895 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1896 ASSERT_TRUE(vec);
1897
1898 /* Component x comes from v[0]. */
1899 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src);
1900 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]);
1901 ASSERT_EQ(vec->src[0].swizzle[0], 0);
1902
1903 /* Component y comes from v[1]. */
1904 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src);
1905 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]);
1906 ASSERT_EQ(vec->src[1].swizzle[0], 1);
1907
1908 /* Components z and w come from v[2]. */
1909 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src);
1910 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src);
1911 ASSERT_EQ(load_for_z, load_for_w);
1912 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), v[2]);
1913 ASSERT_EQ(vec->src[2].swizzle[0], 2);
1914 ASSERT_EQ(vec->src[3].swizzle[0], 3);
1915 }
1916
TEST_F(nir_combine_stores_test,direct_array_derefs)1917 TEST_F(nir_combine_stores_test, direct_array_derefs)
1918 {
1919 nir_variable **v = create_many_ivec4(nir_var_mem_global, "vec", 2);
1920 nir_variable **s = create_many_int(nir_var_mem_global, "scalar", 2);
1921 nir_variable *out = create_ivec4(nir_var_mem_global, "out");
1922
1923 nir_deref_instr *out_deref = nir_build_deref_var(b, out);
1924
1925 /* Store to vector with mask x. */
1926 nir_store_deref(b, out_deref, nir_load_var(b, v[0]),
1927 1 << 0);
1928
1929 /* Store to vector with mask yz. */
1930 nir_store_deref(b, out_deref, nir_load_var(b, v[1]),
1931 (1 << 2) | (1 << 1));
1932
1933 /* Store to vector[2], overlapping with previous store. */
1934 nir_store_deref(b,
1935 nir_build_deref_array_imm(b, out_deref, 2),
1936 nir_load_var(b, s[0]),
1937 1 << 0);
1938
1939 /* Store to vector[3], no overlap. */
1940 nir_store_deref(b,
1941 nir_build_deref_array_imm(b, out_deref, 3),
1942 nir_load_var(b, s[1]),
1943 1 << 0);
1944
1945 nir_validate_shader(b->shader, NULL);
1946
1947 bool progress = nir_opt_combine_stores(b->shader, nir_var_mem_global);
1948 ASSERT_TRUE(progress);
1949
1950 nir_validate_shader(b->shader, NULL);
1951
1952 /* Clean up to verify from where the values in combined store are coming. */
1953 nir_copy_prop(b->shader);
1954 nir_opt_dce(b->shader);
1955
1956 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1957 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1958 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1959 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1960
1961 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1962 ASSERT_TRUE(vec);
1963
1964 /* Component x comes from v[0]. */
1965 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src);
1966 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]);
1967 ASSERT_EQ(vec->src[0].swizzle[0], 0);
1968
1969 /* Component y comes from v[1]. */
1970 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src);
1971 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]);
1972 ASSERT_EQ(vec->src[1].swizzle[0], 1);
1973
1974 /* Components z comes from s[0]. */
1975 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src);
1976 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), s[0]);
1977 ASSERT_EQ(vec->src[2].swizzle[0], 0);
1978
1979 /* Component w comes from s[1]. */
1980 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src);
1981 ASSERT_EQ(nir_intrinsic_get_var(load_for_w, 0), s[1]);
1982 ASSERT_EQ(vec->src[3].swizzle[0], 0);
1983 }
1984
1985 static int64_t
vec_src_comp_as_int(nir_src src,unsigned comp)1986 vec_src_comp_as_int(nir_src src, unsigned comp)
1987 {
1988 if (nir_src_is_const(src))
1989 return nir_src_comp_as_int(src, comp);
1990
1991 assert(src.is_ssa);
1992 nir_ssa_scalar s = { src.ssa, comp };
1993 assert(nir_op_is_vec(nir_ssa_scalar_alu_op(s)));
1994 return nir_ssa_scalar_as_int(nir_ssa_scalar_chase_alu_src(s, comp));
1995 }
1996
TEST_F(nir_combine_stores_test,store_volatile)1997 TEST_F(nir_combine_stores_test, store_volatile)
1998 {
1999 nir_variable *out = create_ivec4(nir_var_shader_out, "out");
2000
2001 nir_store_var(b, out, nir_imm_ivec4(b, 0, 0, 0, 0), 1 << 0);
2002 nir_store_var(b, out, nir_imm_ivec4(b, 1, 1, 1, 1), 1 << 1);
2003 nir_store_var_volatile(b, out, nir_imm_ivec4(b, -1, -2, -3, -4), 0xf);
2004 nir_store_var(b, out, nir_imm_ivec4(b, 2, 2, 2, 2), 1 << 2);
2005 nir_store_var(b, out, nir_imm_ivec4(b, 3, 3, 3, 3), 1 << 3);
2006
2007 nir_validate_shader(b->shader, NULL);
2008
2009 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
2010 ASSERT_TRUE(progress);
2011
2012 nir_validate_shader(b->shader, NULL);
2013
2014 /* Clean up the stored values */
2015 nir_opt_constant_folding(b->shader);
2016 nir_opt_dce(b->shader);
2017
2018 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
2019
2020 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
2021 ASSERT_EQ(nir_intrinsic_write_mask(first), 0x3);
2022 ASSERT_EQ(vec_src_comp_as_int(first->src[1], 0), 0);
2023 ASSERT_EQ(vec_src_comp_as_int(first->src[1], 1), 1);
2024
2025 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
2026 ASSERT_EQ(nir_intrinsic_write_mask(second), 0xf);
2027 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 0), -1);
2028 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 1), -2);
2029 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 2), -3);
2030 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 3), -4);
2031
2032 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
2033 ASSERT_EQ(nir_intrinsic_write_mask(third), 0xc);
2034 ASSERT_EQ(vec_src_comp_as_int(third->src[1], 2), 2);
2035 ASSERT_EQ(vec_src_comp_as_int(third->src[1], 3), 3);
2036 }
2037
TEST_F(nir_split_vars_test,simple_split)2038 TEST_F(nir_split_vars_test, simple_split)
2039 {
2040 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2041 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2042 "temp");
2043 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2044 for (int i = 0; i < 4; i++)
2045 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2046
2047 nir_validate_shader(b->shader, NULL);
2048 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2049 ASSERT_EQ(count_function_temp_vars(), 1);
2050
2051 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2052 EXPECT_TRUE(progress);
2053
2054 nir_validate_shader(b->shader, NULL);
2055 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2056 ASSERT_EQ(count_function_temp_vars(), 4);
2057 }
2058
TEST_F(nir_split_vars_test,simple_no_split_array_struct)2059 TEST_F(nir_split_vars_test, simple_no_split_array_struct)
2060 {
2061 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2062 struct glsl_struct_field field;
2063
2064 field.type = glsl_float_type();
2065 field.name = ralloc_asprintf(b->shader, "field1");
2066 field.location = -1;
2067 field.offset = 0;
2068
2069 const struct glsl_type *st_type = glsl_struct_type(&field, 1, "struct", false);
2070 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(st_type, 4, 0),
2071 "temp");
2072
2073 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), "temp2");
2074
2075 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2076 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2077 for (int i = 0; i < 4; i++)
2078 nir_store_deref(b, nir_build_deref_array_imm(b, temp2_deref, i), nir_load_var(b, in[i]), 1);
2079
2080 for (int i = 0; i < 4; i++)
2081 nir_store_deref(b, nir_build_deref_struct(b, nir_build_deref_array_imm(b, temp_deref, i), 0), nir_load_var(b, in[i]), 1);
2082
2083 nir_validate_shader(b->shader, NULL);
2084 ASSERT_EQ(count_derefs(nir_deref_type_array), 8);
2085 ASSERT_EQ(count_derefs(nir_deref_type_struct), 4);
2086 ASSERT_EQ(count_function_temp_vars(), 2);
2087
2088 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2089 EXPECT_TRUE(progress);
2090
2091 nir_validate_shader(b->shader, NULL);
2092
2093 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2094 ASSERT_EQ(count_derefs(nir_deref_type_struct), 4);
2095 for (int i = 0; i < 4; i++) {
2096 nir_deref_instr *deref = get_deref(nir_deref_type_array, i);
2097 ASSERT_TRUE(deref);
2098 ASSERT_TRUE(glsl_type_is_struct(deref->type));
2099 }
2100
2101 ASSERT_EQ(count_function_temp_vars(), 5);
2102 }
2103
TEST_F(nir_split_vars_test,simple_split_shader_temp)2104 TEST_F(nir_split_vars_test, simple_split_shader_temp)
2105 {
2106 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2107 nir_variable *temp = create_var(nir_var_shader_temp, glsl_array_type(glsl_int_type(), 4, 0),
2108 "temp");
2109 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2110
2111 for (int i = 0; i < 4; i++)
2112 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2113
2114 nir_validate_shader(b->shader, NULL);
2115 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2116 ASSERT_EQ(count_shader_temp_vars(), 1);
2117
2118 bool progress = nir_split_array_vars(b->shader, nir_var_shader_temp);
2119 EXPECT_TRUE(progress);
2120
2121 nir_validate_shader(b->shader, NULL);
2122 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2123 ASSERT_EQ(count_shader_temp_vars(), 4);
2124 }
2125
TEST_F(nir_split_vars_test,simple_oob)2126 TEST_F(nir_split_vars_test, simple_oob)
2127 {
2128 nir_variable **in = create_many_int(nir_var_shader_in, "in", 6);
2129 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2130 "temp");
2131 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2132
2133 for (int i = 0; i < 6; i++)
2134 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2135
2136 nir_validate_shader(b->shader, NULL);
2137 ASSERT_EQ(count_derefs(nir_deref_type_array), 6);
2138 ASSERT_EQ(count_function_temp_vars(), 1);
2139
2140 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2141 EXPECT_TRUE(progress);
2142
2143 nir_validate_shader(b->shader, NULL);
2144 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2145 ASSERT_EQ(count_function_temp_vars(), 4);
2146 }
2147
TEST_F(nir_split_vars_test,simple_unused)2148 TEST_F(nir_split_vars_test, simple_unused)
2149 {
2150 nir_variable **in = create_many_int(nir_var_shader_in, "in", 2);
2151 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2152 "temp");
2153 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2154
2155 for (int i = 0; i < 2; i++)
2156 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2157
2158 nir_validate_shader(b->shader, NULL);
2159 ASSERT_EQ(count_derefs(nir_deref_type_array), 2);
2160 ASSERT_EQ(count_function_temp_vars(), 1);
2161
2162 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2163 EXPECT_TRUE(progress);
2164
2165 nir_validate_shader(b->shader, NULL);
2166 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2167 /* this pass doesn't remove the unused ones */
2168 ASSERT_EQ(count_function_temp_vars(), 4);
2169 }
2170
TEST_F(nir_split_vars_test,two_level_split)2171 TEST_F(nir_split_vars_test, two_level_split)
2172 {
2173 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2174 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 4, 0), 4, 0),
2175 "temp");
2176 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2177 for (int i = 0; i < 4; i++) {
2178 nir_deref_instr *level0 = nir_build_deref_array_imm(b, temp_deref, i);
2179 for (int j = 0; j < 4; j++) {
2180 nir_deref_instr *level1 = nir_build_deref_array_imm(b, level0, j);
2181 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1);
2182 }
2183 }
2184
2185 nir_validate_shader(b->shader, NULL);
2186 ASSERT_EQ(count_derefs(nir_deref_type_array), 20);
2187 ASSERT_EQ(count_function_temp_vars(), 1);
2188
2189 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2190 EXPECT_TRUE(progress);
2191
2192 nir_validate_shader(b->shader, NULL);
2193 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2194 ASSERT_EQ(count_function_temp_vars(), 16);
2195 }
2196
TEST_F(nir_split_vars_test,simple_dont_split)2197 TEST_F(nir_split_vars_test, simple_dont_split)
2198 {
2199 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2200 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2201 "temp");
2202 nir_variable *ind = create_int(nir_var_shader_in, "ind");
2203
2204 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind);
2205 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2206
2207 for (int i = 0; i < 4; i++)
2208 nir_store_deref(b, nir_build_deref_array(b, temp_deref, &ind_deref->dest.ssa), nir_load_var(b, in[i]), 1);
2209
2210 nir_validate_shader(b->shader, NULL);
2211 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2212 ASSERT_EQ(count_function_temp_vars(), 1);
2213
2214 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2215 EXPECT_FALSE(progress);
2216
2217 nir_validate_shader(b->shader, NULL);
2218 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2219 ASSERT_EQ(count_function_temp_vars(), 1);
2220 }
2221
TEST_F(nir_split_vars_test,twolevel_dont_split_lvl_0)2222 TEST_F(nir_split_vars_test, twolevel_dont_split_lvl_0)
2223 {
2224 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2225 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 6, 0), 4, 0),
2226 "temp");
2227 nir_variable *ind = create_int(nir_var_shader_in, "ind");
2228
2229 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind);
2230 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2231
2232 for (int i = 0; i < 4; i++) {
2233 nir_deref_instr *level0 = nir_build_deref_array(b, temp_deref, &ind_deref->dest.ssa);
2234 for (int j = 0; j < 6; j++) {
2235 nir_deref_instr *level1 = nir_build_deref_array_imm(b, level0, j);
2236 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1);
2237 }
2238 }
2239
2240 nir_validate_shader(b->shader, NULL);
2241 ASSERT_EQ(count_derefs(nir_deref_type_array), 28);
2242 ASSERT_EQ(count_function_temp_vars(), 1);
2243
2244 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2245 EXPECT_TRUE(progress);
2246
2247 nir_validate_shader(b->shader, NULL);
2248 ASSERT_EQ(count_derefs(nir_deref_type_array), 24);
2249 ASSERT_EQ(count_function_temp_vars(), 6);
2250 }
2251
TEST_F(nir_split_vars_test,twolevel_dont_split_lvl_1)2252 TEST_F(nir_split_vars_test, twolevel_dont_split_lvl_1)
2253 {
2254 nir_variable **in = create_many_int(nir_var_shader_in, "in", 6);
2255 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 6, 0), 4, 0),
2256 "temp");
2257 nir_variable *ind = create_int(nir_var_shader_in, "ind");
2258
2259 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind);
2260 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2261
2262 for (int i = 0; i < 4; i++) {
2263 nir_deref_instr *level0 = nir_build_deref_array_imm(b, temp_deref, i);
2264 for (int j = 0; j < 6; j++) {
2265 /* just add the inner index to get some different derefs */
2266 nir_deref_instr *level1 = nir_build_deref_array(b, level0, nir_iadd(b, &ind_deref->dest.ssa, nir_imm_int(b, j)));
2267 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1);
2268 }
2269 }
2270
2271 nir_validate_shader(b->shader, NULL);
2272 ASSERT_EQ(count_derefs(nir_deref_type_array), 28);
2273 ASSERT_EQ(count_function_temp_vars(), 1);
2274
2275 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2276 EXPECT_TRUE(progress);
2277
2278 nir_validate_shader(b->shader, NULL);
2279 ASSERT_EQ(count_derefs(nir_deref_type_array), 24);
2280 ASSERT_EQ(count_function_temp_vars(), 4);
2281 }
2282
TEST_F(nir_split_vars_test,split_multiple_store)2283 TEST_F(nir_split_vars_test, split_multiple_store)
2284 {
2285 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2286 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2287 "temp");
2288 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2289 "temp2");
2290
2291 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2292 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2293
2294 for (int i = 0; i < 4; i++)
2295 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2296
2297 for (int i = 0; i < 4; i++)
2298 nir_store_deref(b, nir_build_deref_array_imm(b, temp2_deref, i), nir_load_var(b, in[i]), 1);
2299
2300 nir_validate_shader(b->shader, NULL);
2301 ASSERT_EQ(count_derefs(nir_deref_type_array), 8);
2302 ASSERT_EQ(count_function_temp_vars(), 2);
2303
2304 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2305 EXPECT_TRUE(progress);
2306
2307 nir_validate_shader(b->shader, NULL);
2308 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2309 ASSERT_EQ(count_function_temp_vars(), 8);
2310 }
2311
TEST_F(nir_split_vars_test,split_load_store)2312 TEST_F(nir_split_vars_test, split_load_store)
2313 {
2314 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2315 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2316 "temp");
2317 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2318 "temp2");
2319
2320 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2321 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2322
2323 for (int i = 0; i < 4; i++)
2324 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2325
2326 for (int i = 0; i < 4; i++) {
2327 nir_deref_instr *store_deref = nir_build_deref_array_imm(b, temp2_deref, i);
2328 nir_deref_instr *load_deref = nir_build_deref_array_imm(b, temp_deref, i);
2329 nir_store_deref(b, store_deref, nir_load_deref(b, load_deref), 1);
2330 }
2331
2332 nir_validate_shader(b->shader, NULL);
2333 ASSERT_EQ(count_derefs(nir_deref_type_array), 12);
2334 ASSERT_EQ(count_function_temp_vars(), 2);
2335
2336 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2337 EXPECT_TRUE(progress);
2338
2339 nir_validate_shader(b->shader, NULL);
2340 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2341 ASSERT_EQ(count_function_temp_vars(), 8);
2342 }
2343
TEST_F(nir_split_vars_test,split_copy)2344 TEST_F(nir_split_vars_test, split_copy)
2345 {
2346 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2347 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2348 "temp");
2349 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2350 "temp2");
2351
2352 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2353 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2354
2355 for (int i = 0; i < 4; i++)
2356 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2357
2358 for (int i = 0; i < 4; i++) {
2359 nir_deref_instr *store_deref = nir_build_deref_array_imm(b, temp2_deref, i);
2360 nir_deref_instr *load_deref = nir_build_deref_array_imm(b, temp_deref, i);
2361 nir_copy_deref(b, store_deref, load_deref);
2362 }
2363
2364 nir_validate_shader(b->shader, NULL);
2365 ASSERT_EQ(count_derefs(nir_deref_type_array), 12);
2366 ASSERT_EQ(count_function_temp_vars(), 2);
2367
2368 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2369 EXPECT_TRUE(progress);
2370
2371 nir_validate_shader(b->shader, NULL);
2372 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2373 ASSERT_EQ(count_function_temp_vars(), 8);
2374 }
2375
TEST_F(nir_split_vars_test,split_wildcard_copy)2376 TEST_F(nir_split_vars_test, split_wildcard_copy)
2377 {
2378 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2379 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2380 "temp");
2381 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2382 "temp2");
2383
2384 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2385 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2386
2387 for (int i = 0; i < 4; i++)
2388 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2389
2390 nir_deref_instr *src_wildcard = nir_build_deref_array_wildcard(b, temp_deref);
2391 nir_deref_instr *dst_wildcard = nir_build_deref_array_wildcard(b, temp2_deref);
2392
2393 nir_copy_deref(b, dst_wildcard, src_wildcard);
2394
2395 nir_validate_shader(b->shader, NULL);
2396 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2397 ASSERT_EQ(count_derefs(nir_deref_type_array_wildcard), 2);
2398 ASSERT_EQ(count_function_temp_vars(), 2);
2399 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 1);
2400
2401 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2402 EXPECT_TRUE(progress);
2403
2404 nir_validate_shader(b->shader, NULL);
2405 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2406 ASSERT_EQ(count_derefs(nir_deref_type_array_wildcard), 0);
2407 ASSERT_EQ(count_function_temp_vars(), 8);
2408 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 4);
2409 }
2410
TEST_F(nir_remove_dead_variables_test,pointer_initializer_used)2411 TEST_F(nir_remove_dead_variables_test, pointer_initializer_used)
2412 {
2413 nir_variable *x = create_int(nir_var_shader_temp, "x");
2414 nir_variable *y = create_int(nir_var_shader_temp, "y");
2415 y->pointer_initializer = x;
2416 nir_variable *out = create_int(nir_var_shader_out, "out");
2417
2418 nir_validate_shader(b->shader, NULL);
2419
2420 nir_copy_var(b, out, y);
2421
2422 bool progress = nir_remove_dead_variables(b->shader, nir_var_all, NULL);
2423 EXPECT_FALSE(progress);
2424
2425 nir_validate_shader(b->shader, NULL);
2426
2427 unsigned count = 0;
2428 nir_foreach_variable_in_shader(var, b->shader)
2429 count++;
2430
2431 ASSERT_EQ(count, 3);
2432 }
2433
TEST_F(nir_remove_dead_variables_test,pointer_initializer_dead)2434 TEST_F(nir_remove_dead_variables_test, pointer_initializer_dead)
2435 {
2436 nir_variable *x = create_int(nir_var_shader_temp, "x");
2437 nir_variable *y = create_int(nir_var_shader_temp, "y");
2438 nir_variable *z = create_int(nir_var_shader_temp, "z");
2439 y->pointer_initializer = x;
2440 z->pointer_initializer = y;
2441
2442 nir_validate_shader(b->shader, NULL);
2443
2444 bool progress = nir_remove_dead_variables(b->shader, nir_var_all, NULL);
2445 EXPECT_TRUE(progress);
2446
2447 nir_validate_shader(b->shader, NULL);
2448
2449 unsigned count = 0;
2450 nir_foreach_variable_in_shader(var, b->shader)
2451 count++;
2452
2453 ASSERT_EQ(count, 0);
2454 }
2455
2456
2457