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