nir: Use a single list for all shader variables
[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 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 *mem_ctx;
96 void *lin_ctx;
97
98 nir_builder *b;
99 };
100
101 nir_vars_test::nir_vars_test()
102 {
103 glsl_type_singleton_init_or_ref();
104
105 mem_ctx = ralloc_context(NULL);
106 lin_ctx = linear_alloc_parent(mem_ctx, 0);
107 static const nir_shader_compiler_options options = { };
108 b = rzalloc(mem_ctx, nir_builder);
109 nir_builder_init_simple_shader(b, mem_ctx, MESA_SHADER_COMPUTE, &options);
110 }
111
112 nir_vars_test::~nir_vars_test()
113 {
114 if (HasFailure()) {
115 printf("\nShader from the failed test:\n\n");
116 nir_print_shader(b->shader, stdout);
117 }
118
119 ralloc_free(mem_ctx);
120
121 glsl_type_singleton_decref();
122 }
123
124 unsigned
125 nir_vars_test::count_intrinsics(nir_intrinsic_op intrinsic)
126 {
127 unsigned count = 0;
128 nir_foreach_block(block, b->impl) {
129 nir_foreach_instr(instr, block) {
130 if (instr->type != nir_instr_type_intrinsic)
131 continue;
132 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
133 if (intrin->intrinsic == intrinsic)
134 count++;
135 }
136 }
137 return count;
138 }
139
140 unsigned
141 nir_vars_test::count_derefs(nir_deref_type deref_type)
142 {
143 unsigned count = 0;
144 nir_foreach_block(block, b->impl) {
145 nir_foreach_instr(instr, block) {
146 if (instr->type != nir_instr_type_deref)
147 continue;
148 nir_deref_instr *intrin = nir_instr_as_deref(instr);
149 if (intrin->deref_type == deref_type)
150 count++;
151 }
152 }
153 return count;
154 }
155
156 nir_intrinsic_instr *
157 nir_vars_test::get_intrinsic(nir_intrinsic_op intrinsic,
158 unsigned index)
159 {
160 nir_foreach_block(block, b->impl) {
161 nir_foreach_instr(instr, block) {
162 if (instr->type != nir_instr_type_intrinsic)
163 continue;
164 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
165 if (intrin->intrinsic == intrinsic) {
166 if (index == 0)
167 return intrin;
168 index--;
169 }
170 }
171 }
172 return NULL;
173 }
174
175 nir_deref_instr *
176 nir_vars_test::get_deref(nir_deref_type deref_type,
177 unsigned index)
178 {
179 nir_foreach_block(block, b->impl) {
180 nir_foreach_instr(instr, block) {
181 if (instr->type != nir_instr_type_deref)
182 continue;
183 nir_deref_instr *deref = nir_instr_as_deref(instr);
184 if (deref->deref_type == deref_type) {
185 if (index == 0)
186 return deref;
187 index--;
188 }
189 }
190 }
191 return NULL;
192 }
193
194 /* Allow grouping the tests while still sharing the helpers. */
195 class nir_redundant_load_vars_test : public nir_vars_test {};
196 class nir_copy_prop_vars_test : public nir_vars_test {};
197 class nir_dead_write_vars_test : public nir_vars_test {};
198 class nir_combine_stores_test : public nir_vars_test {};
199 class nir_split_vars_test : public nir_vars_test {};
200
201 } // namespace
202
203 static nir_ssa_def *
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
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
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_shader_in, "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
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_shader_in, "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
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_shader_in, "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
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
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_ssbo, "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
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
398 TEST_F(nir_copy_prop_vars_test, self_copy)
399 {
400 nir_variable *v = create_int(nir_var_mem_ssbo, "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
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
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
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
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
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
583 TEST_F(nir_copy_prop_vars_test, self_copy_volatile)
584 {
585 nir_variable *v = create_int(nir_var_mem_ssbo, "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
614 TEST_F(nir_copy_prop_vars_test, memory_barrier_in_two_blocks)
615 {
616 nir_variable **v = create_many_int(nir_var_mem_ssbo, "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_ssbo);
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
640 TEST_F(nir_redundant_load_vars_test, acquire_barrier_prevents_load_removal)
641 {
642 nir_variable **x = create_many_int(nir_var_mem_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
717 TEST_F(nir_redundant_load_vars_test, release_barrier_allows_load_removal)
718 {
719 nir_variable **x = create_many_int(nir_var_mem_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
789 TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation)
790 {
791 nir_variable **x = create_many_int(nir_var_mem_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
871 TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation)
872 {
873 nir_variable **x = create_many_int(nir_var_mem_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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_ssbo, "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_ssbo);
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
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
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_ssbo, "in0");
1080 nir_variable *in1 = create_ivec2(nir_var_mem_ssbo, "in1");
1081 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
1082 nir_variable *out = create_int(nir_var_mem_ssbo, "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
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_ssbo, "in0");
1116 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "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
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_ssbo, "in0");
1140 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
1141 nir_variable *out = create_ivec2(nir_var_mem_ssbo, "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
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_ssbo, "vec");
1174 nir_variable *out0 = create_int(nir_var_mem_ssbo, "out0");
1175 nir_variable *out1 = create_ivec2(nir_var_mem_ssbo, "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
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_ssbo, "vec");
1219 nir_variable *idx = create_int(nir_var_mem_ssbo, "idx");
1220 nir_variable *out = create_int(nir_var_mem_ssbo, "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
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_ssbo, "vec");
1256 nir_variable *idx = create_int(nir_var_mem_ssbo, "idx");
1257 nir_variable **out = create_many_int(nir_var_mem_ssbo, "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
1291 TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref)
1292 {
1293 nir_variable *arr = create_var(nir_var_mem_ssbo,
1294 glsl_array_type(glsl_int_type(), 10, 0),
1295 "arr");
1296 nir_variable *idx = create_int(nir_var_mem_ssbo, "idx");
1297 nir_variable *out = create_int(nir_var_mem_ssbo, "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
1330 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block)
1331 {
1332 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2);
1333
1334 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1335
1336 bool progress = nir_opt_dead_write_vars(b->shader);
1337 ASSERT_FALSE(progress);
1338 }
1339
1340 TEST_F(nir_dead_write_vars_test, no_dead_writes_different_components_in_block)
1341 {
1342 nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3);
1343
1344 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
1345 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1 << 1);
1346
1347 bool progress = nir_opt_dead_write_vars(b->shader);
1348 ASSERT_FALSE(progress);
1349 }
1350
1351 TEST_F(nir_dead_write_vars_test, volatile_write)
1352 {
1353 nir_variable *v = create_int(nir_var_mem_ssbo, "v");
1354
1355 nir_store_var(b, v, nir_imm_int(b, 0), 0x1);
1356 nir_store_var_volatile(b, v, nir_imm_int(b, 1), 0x1);
1357 nir_store_var(b, v, nir_imm_int(b, 2), 0x1);
1358
1359 /* Our approach here is a bit scorched-earth. We expect the volatile store
1360 * in the middle to cause both that store and the one before it to be kept.
1361 * Technically, volatile only prevents combining the volatile store with
1362 * another store and one could argue that the store before the volatile and
1363 * the one after it could be combined. However, it seems safer to just
1364 * treat a volatile store like an atomic and prevent any combining across
1365 * it.
1366 */
1367 bool progress = nir_opt_dead_write_vars(b->shader);
1368 ASSERT_FALSE(progress);
1369 }
1370
1371 TEST_F(nir_dead_write_vars_test, volatile_copies)
1372 {
1373 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2);
1374
1375 nir_copy_var(b, v[0], v[1]);
1376 nir_copy_deref_with_access(b, nir_build_deref_var(b, v[0]),
1377 nir_build_deref_var(b, v[1]),
1378 ACCESS_VOLATILE, (gl_access_qualifier)0);
1379 nir_copy_var(b, v[0], v[1]);
1380
1381 /* Our approach here is a bit scorched-earth. We expect the volatile store
1382 * in the middle to cause both that store and the one before it to be kept.
1383 * Technically, volatile only prevents combining the volatile store with
1384 * another store and one could argue that the store before the volatile and
1385 * the one after it could be combined. However, it seems safer to just
1386 * treat a volatile store like an atomic and prevent any combining across
1387 * it.
1388 */
1389 bool progress = nir_opt_dead_write_vars(b->shader);
1390 ASSERT_FALSE(progress);
1391 }
1392
1393 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_if_statement)
1394 {
1395 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 6);
1396
1397 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1);
1398 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1);
1399
1400 /* Each arm of the if statement will overwrite one store. */
1401 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
1402 nir_store_var(b, v[2], nir_load_var(b, v[4]), 1);
1403
1404 nir_push_else(b, if_stmt);
1405 nir_store_var(b, v[3], nir_load_var(b, v[5]), 1);
1406
1407 nir_pop_if(b, if_stmt);
1408
1409 bool progress = nir_opt_dead_write_vars(b->shader);
1410 ASSERT_FALSE(progress);
1411 }
1412
1413 TEST_F(nir_dead_write_vars_test, no_dead_writes_in_loop_statement)
1414 {
1415 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
1416
1417 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1418
1419 /* Loop will write other value. Since it might not be executed, it doesn't
1420 * kill the first write.
1421 */
1422 nir_loop *loop = nir_push_loop(b);
1423
1424 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
1425 nir_jump(b, nir_jump_break);
1426 nir_pop_if(b, if_stmt);
1427
1428 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
1429 nir_pop_loop(b, loop);
1430
1431 bool progress = nir_opt_dead_write_vars(b->shader);
1432 ASSERT_FALSE(progress);
1433 }
1434
1435 TEST_F(nir_dead_write_vars_test, dead_write_in_block)
1436 {
1437 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
1438
1439 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1440 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1441 nir_store_var(b, v[0], load_v2, 1);
1442
1443 bool progress = nir_opt_dead_write_vars(b->shader);
1444 ASSERT_TRUE(progress);
1445
1446 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1447
1448 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1449 ASSERT_TRUE(store->src[1].is_ssa);
1450 EXPECT_EQ(store->src[1].ssa, load_v2);
1451 }
1452
1453 TEST_F(nir_dead_write_vars_test, dead_write_components_in_block)
1454 {
1455 nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3);
1456
1457 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
1458 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1459 nir_store_var(b, v[0], load_v2, 1 << 0);
1460
1461 bool progress = nir_opt_dead_write_vars(b->shader);
1462 ASSERT_TRUE(progress);
1463
1464 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1465
1466 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1467 ASSERT_TRUE(store->src[1].is_ssa);
1468 EXPECT_EQ(store->src[1].ssa, load_v2);
1469 }
1470
1471
1472 /* TODO: The DISABLED tests below depend on the dead write removal be able to
1473 * identify dead writes between multiple blocks. This is still not
1474 * implemented.
1475 */
1476
1477 TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_in_two_blocks)
1478 {
1479 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
1480
1481 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1482 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1483
1484 /* Causes the stores to be in different blocks. */
1485 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1486
1487 nir_store_var(b, v[0], load_v2, 1);
1488
1489 bool progress = nir_opt_dead_write_vars(b->shader);
1490 ASSERT_TRUE(progress);
1491
1492 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1493
1494 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1495 ASSERT_TRUE(store->src[1].is_ssa);
1496 EXPECT_EQ(store->src[1].ssa, load_v2);
1497 }
1498
1499 TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_components_in_two_blocks)
1500 {
1501 nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3);
1502
1503 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
1504
1505 /* Causes the stores to be in different blocks. */
1506 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1507
1508 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1509 nir_store_var(b, v[0], load_v2, 1 << 0);
1510
1511 bool progress = nir_opt_dead_write_vars(b->shader);
1512 ASSERT_TRUE(progress);
1513
1514 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
1515
1516 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
1517 ASSERT_TRUE(store->src[1].is_ssa);
1518 EXPECT_EQ(store->src[1].ssa, load_v2);
1519 }
1520
1521 TEST_F(nir_dead_write_vars_test, DISABLED_dead_writes_in_if_statement)
1522 {
1523 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 4);
1524
1525 /* Both branches will overwrite, making the previous store dead. */
1526 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1527
1528 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
1529 nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
1530 nir_store_var(b, v[0], load_v2, 1);
1531
1532 nir_push_else(b, if_stmt);
1533 nir_ssa_def *load_v3 = nir_load_var(b, v[3]);
1534 nir_store_var(b, v[0], load_v3, 1);
1535
1536 nir_pop_if(b, if_stmt);
1537
1538 bool progress = nir_opt_dead_write_vars(b->shader);
1539 ASSERT_TRUE(progress);
1540 EXPECT_EQ(2, count_intrinsics(nir_intrinsic_store_deref));
1541
1542 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
1543 ASSERT_TRUE(first_store->src[1].is_ssa);
1544 EXPECT_EQ(first_store->src[1].ssa, load_v2);
1545
1546 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1);
1547 ASSERT_TRUE(second_store->src[1].is_ssa);
1548 EXPECT_EQ(second_store->src[1].ssa, load_v3);
1549 }
1550
1551 TEST_F(nir_dead_write_vars_test, DISABLED_memory_barrier_in_two_blocks)
1552 {
1553 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2);
1554
1555 nir_store_var(b, v[0], nir_imm_int(b, 1), 1);
1556 nir_store_var(b, v[1], nir_imm_int(b, 2), 1);
1557
1558 /* Split into many blocks. */
1559 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1560
1561 /* Because it is before the barrier, this will kill the previous store to that target. */
1562 nir_store_var(b, v[0], nir_imm_int(b, 3), 1);
1563
1564 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQ_REL,
1565 nir_var_mem_ssbo);
1566
1567 nir_store_var(b, v[1], nir_imm_int(b, 4), 1);
1568
1569 bool progress = nir_opt_dead_write_vars(b->shader);
1570 ASSERT_TRUE(progress);
1571
1572 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
1573 }
1574
1575 TEST_F(nir_dead_write_vars_test, DISABLED_unrelated_barrier_in_two_blocks)
1576 {
1577 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
1578 nir_variable *out = create_int(nir_var_shader_out, "out");
1579
1580 nir_store_var(b, out, nir_load_var(b, v[1]), 1);
1581 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
1582
1583 /* Split into many blocks. */
1584 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
1585
1586 /* Emit vertex will ensure writes to output variables are considered used,
1587 * but should not affect other types of variables. */
1588
1589 nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_emit_vertex)->instr);
1590
1591 nir_store_var(b, out, nir_load_var(b, v[2]), 1);
1592 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
1593
1594 bool progress = nir_opt_dead_write_vars(b->shader);
1595 ASSERT_TRUE(progress);
1596
1597 /* Verify the first write to v[0] was removed. */
1598 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
1599
1600 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
1601 EXPECT_EQ(nir_intrinsic_get_var(first_store, 0), out);
1602
1603 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1);
1604 EXPECT_EQ(nir_intrinsic_get_var(second_store, 0), out);
1605
1606 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2);
1607 EXPECT_EQ(nir_intrinsic_get_var(third_store, 0), v[0]);
1608 }
1609
1610 TEST_F(nir_combine_stores_test, non_overlapping_stores)
1611 {
1612 nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "v", 4);
1613 nir_variable *out = create_ivec4(nir_var_shader_out, "out");
1614
1615 for (int i = 0; i < 4; i++)
1616 nir_store_var(b, out, nir_load_var(b, v[i]), 1 << i);
1617
1618 nir_validate_shader(b->shader, NULL);
1619
1620 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
1621 ASSERT_TRUE(progress);
1622
1623 nir_validate_shader(b->shader, NULL);
1624
1625 /* Clean up to verify from where the values in combined store are coming. */
1626 nir_copy_prop(b->shader);
1627 nir_opt_dce(b->shader);
1628
1629 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1630 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1631 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1632 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1633
1634 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1635 ASSERT_TRUE(vec);
1636 for (int i = 0; i < 4; i++) {
1637 nir_intrinsic_instr *load = nir_src_as_intrinsic(vec->src[i].src);
1638 ASSERT_EQ(load->intrinsic, nir_intrinsic_load_deref);
1639 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[i])
1640 << "Source value for component " << i << " of store is wrong";
1641 ASSERT_EQ(vec->src[i].swizzle[0], i)
1642 << "Source component for component " << i << " of store is wrong";
1643 }
1644 }
1645
1646 TEST_F(nir_combine_stores_test, overlapping_stores)
1647 {
1648 nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "v", 3);
1649 nir_variable *out = create_ivec4(nir_var_shader_out, "out");
1650
1651 /* Make stores with xy, yz and zw masks. */
1652 for (int i = 0; i < 3; i++) {
1653 nir_component_mask_t mask = (1 << i) | (1 << (i + 1));
1654 nir_store_var(b, out, nir_load_var(b, v[i]), mask);
1655 }
1656
1657 nir_validate_shader(b->shader, NULL);
1658
1659 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
1660 ASSERT_TRUE(progress);
1661
1662 nir_validate_shader(b->shader, NULL);
1663
1664 /* Clean up to verify from where the values in combined store are coming. */
1665 nir_copy_prop(b->shader);
1666 nir_opt_dce(b->shader);
1667
1668 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1669 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1670 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1671 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1672
1673 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1674 ASSERT_TRUE(vec);
1675
1676 /* Component x comes from v[0]. */
1677 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src);
1678 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]);
1679 ASSERT_EQ(vec->src[0].swizzle[0], 0);
1680
1681 /* Component y comes from v[1]. */
1682 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src);
1683 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]);
1684 ASSERT_EQ(vec->src[1].swizzle[0], 1);
1685
1686 /* Components z and w come from v[2]. */
1687 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src);
1688 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src);
1689 ASSERT_EQ(load_for_z, load_for_w);
1690 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), v[2]);
1691 ASSERT_EQ(vec->src[2].swizzle[0], 2);
1692 ASSERT_EQ(vec->src[3].swizzle[0], 3);
1693 }
1694
1695 TEST_F(nir_combine_stores_test, direct_array_derefs)
1696 {
1697 nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "vec", 2);
1698 nir_variable **s = create_many_int(nir_var_mem_ssbo, "scalar", 2);
1699 nir_variable *out = create_ivec4(nir_var_mem_ssbo, "out");
1700
1701 nir_deref_instr *out_deref = nir_build_deref_var(b, out);
1702
1703 /* Store to vector with mask x. */
1704 nir_store_deref(b, out_deref, nir_load_var(b, v[0]),
1705 1 << 0);
1706
1707 /* Store to vector with mask yz. */
1708 nir_store_deref(b, out_deref, nir_load_var(b, v[1]),
1709 (1 << 2) | (1 << 1));
1710
1711 /* Store to vector[2], overlapping with previous store. */
1712 nir_store_deref(b,
1713 nir_build_deref_array_imm(b, out_deref, 2),
1714 nir_load_var(b, s[0]),
1715 1 << 0);
1716
1717 /* Store to vector[3], no overlap. */
1718 nir_store_deref(b,
1719 nir_build_deref_array_imm(b, out_deref, 3),
1720 nir_load_var(b, s[1]),
1721 1 << 0);
1722
1723 nir_validate_shader(b->shader, NULL);
1724
1725 bool progress = nir_opt_combine_stores(b->shader, nir_var_mem_ssbo);
1726 ASSERT_TRUE(progress);
1727
1728 nir_validate_shader(b->shader, NULL);
1729
1730 /* Clean up to verify from where the values in combined store are coming. */
1731 nir_copy_prop(b->shader);
1732 nir_opt_dce(b->shader);
1733
1734 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1735 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1736 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1737 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1738
1739 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1740 ASSERT_TRUE(vec);
1741
1742 /* Component x comes from v[0]. */
1743 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src);
1744 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]);
1745 ASSERT_EQ(vec->src[0].swizzle[0], 0);
1746
1747 /* Component y comes from v[1]. */
1748 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src);
1749 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]);
1750 ASSERT_EQ(vec->src[1].swizzle[0], 1);
1751
1752 /* Components z comes from s[0]. */
1753 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src);
1754 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), s[0]);
1755 ASSERT_EQ(vec->src[2].swizzle[0], 0);
1756
1757 /* Component w comes from s[1]. */
1758 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src);
1759 ASSERT_EQ(nir_intrinsic_get_var(load_for_w, 0), s[1]);
1760 ASSERT_EQ(vec->src[3].swizzle[0], 0);
1761 }
1762
1763 static int64_t
1764 vec_src_comp_as_int(nir_src src, unsigned comp)
1765 {
1766 if (nir_src_is_const(src))
1767 return nir_src_comp_as_int(src, comp);
1768
1769 assert(src.is_ssa);
1770 nir_ssa_scalar s = { src.ssa, comp };
1771 assert(nir_op_is_vec(nir_ssa_scalar_alu_op(s)));
1772 return nir_ssa_scalar_as_int(nir_ssa_scalar_chase_alu_src(s, comp));
1773 }
1774
1775 TEST_F(nir_combine_stores_test, store_volatile)
1776 {
1777 nir_variable *out = create_ivec4(nir_var_shader_out, "out");
1778
1779 nir_store_var(b, out, nir_imm_ivec4(b, 0, 0, 0, 0), 1 << 0);
1780 nir_store_var(b, out, nir_imm_ivec4(b, 1, 1, 1, 1), 1 << 1);
1781 nir_store_var_volatile(b, out, nir_imm_ivec4(b, -1, -2, -3, -4), 0xf);
1782 nir_store_var(b, out, nir_imm_ivec4(b, 2, 2, 2, 2), 1 << 2);
1783 nir_store_var(b, out, nir_imm_ivec4(b, 3, 3, 3, 3), 1 << 3);
1784
1785 nir_validate_shader(b->shader, NULL);
1786
1787 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
1788 ASSERT_TRUE(progress);
1789
1790 nir_validate_shader(b->shader, NULL);
1791
1792 /* Clean up the stored values */
1793 nir_opt_constant_folding(b->shader);
1794 nir_opt_dce(b->shader);
1795
1796 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
1797
1798 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
1799 ASSERT_EQ(nir_intrinsic_write_mask(first), 0x3);
1800 ASSERT_EQ(vec_src_comp_as_int(first->src[1], 0), 0);
1801 ASSERT_EQ(vec_src_comp_as_int(first->src[1], 1), 1);
1802
1803 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
1804 ASSERT_EQ(nir_intrinsic_write_mask(second), 0xf);
1805 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 0), -1);
1806 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 1), -2);
1807 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 2), -3);
1808 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 3), -4);
1809
1810 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
1811 ASSERT_EQ(nir_intrinsic_write_mask(third), 0xc);
1812 ASSERT_EQ(vec_src_comp_as_int(third->src[1], 2), 2);
1813 ASSERT_EQ(vec_src_comp_as_int(third->src[1], 3), 3);
1814 }
1815
1816 TEST_F(nir_split_vars_test, simple_split)
1817 {
1818 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
1819 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
1820 "temp");
1821 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1822 for (int i = 0; i < 4; i++)
1823 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
1824
1825 nir_validate_shader(b->shader, NULL);
1826 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
1827 ASSERT_EQ(count_function_temp_vars(), 1);
1828
1829 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
1830 EXPECT_TRUE(progress);
1831
1832 nir_validate_shader(b->shader, NULL);
1833 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
1834 ASSERT_EQ(count_function_temp_vars(), 4);
1835 }
1836
1837 TEST_F(nir_split_vars_test, simple_no_split_array_struct)
1838 {
1839 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
1840 struct glsl_struct_field field;
1841
1842 field.type = glsl_float_type();
1843 field.name = ralloc_asprintf(b, "field1");
1844 field.location = -1;
1845 field.offset = 0;
1846
1847 const struct glsl_type *st_type = glsl_struct_type(&field, 1, "struct", false);
1848 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(st_type, 4, 0),
1849 "temp");
1850
1851 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), "temp2");
1852
1853 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1854 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
1855 for (int i = 0; i < 4; i++)
1856 nir_store_deref(b, nir_build_deref_array_imm(b, temp2_deref, i), nir_load_var(b, in[i]), 1);
1857
1858 for (int i = 0; i < 4; i++)
1859 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);
1860
1861 nir_validate_shader(b->shader, NULL);
1862 ASSERT_EQ(count_derefs(nir_deref_type_array), 8);
1863 ASSERT_EQ(count_derefs(nir_deref_type_struct), 4);
1864 ASSERT_EQ(count_function_temp_vars(), 2);
1865
1866 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
1867 EXPECT_TRUE(progress);
1868
1869 nir_validate_shader(b->shader, NULL);
1870
1871 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
1872 ASSERT_EQ(count_derefs(nir_deref_type_struct), 4);
1873 for (int i = 0; i < 4; i++) {
1874 nir_deref_instr *deref = get_deref(nir_deref_type_array, i);
1875 ASSERT_TRUE(deref);
1876 ASSERT_TRUE(glsl_type_is_struct(deref->type));
1877 }
1878
1879 ASSERT_EQ(count_function_temp_vars(), 5);
1880 }
1881
1882 TEST_F(nir_split_vars_test, simple_split_shader_temp)
1883 {
1884 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
1885 nir_variable *temp = create_var(nir_var_shader_temp, glsl_array_type(glsl_int_type(), 4, 0),
1886 "temp");
1887 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1888
1889 for (int i = 0; i < 4; i++)
1890 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
1891
1892 nir_validate_shader(b->shader, NULL);
1893 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
1894 ASSERT_EQ(count_shader_temp_vars(), 1);
1895
1896 bool progress = nir_split_array_vars(b->shader, nir_var_shader_temp);
1897 EXPECT_TRUE(progress);
1898
1899 nir_validate_shader(b->shader, NULL);
1900 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
1901 ASSERT_EQ(count_shader_temp_vars(), 4);
1902 }
1903
1904 TEST_F(nir_split_vars_test, simple_oob)
1905 {
1906 nir_variable **in = create_many_int(nir_var_shader_in, "in", 6);
1907 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
1908 "temp");
1909 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1910
1911 for (int i = 0; i < 6; i++)
1912 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
1913
1914 nir_validate_shader(b->shader, NULL);
1915 ASSERT_EQ(count_derefs(nir_deref_type_array), 6);
1916 ASSERT_EQ(count_function_temp_vars(), 1);
1917
1918 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
1919 EXPECT_TRUE(progress);
1920
1921 nir_validate_shader(b->shader, NULL);
1922 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
1923 ASSERT_EQ(count_function_temp_vars(), 4);
1924 }
1925
1926 TEST_F(nir_split_vars_test, simple_unused)
1927 {
1928 nir_variable **in = create_many_int(nir_var_shader_in, "in", 2);
1929 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
1930 "temp");
1931 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1932
1933 for (int i = 0; i < 2; i++)
1934 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
1935
1936 nir_validate_shader(b->shader, NULL);
1937 ASSERT_EQ(count_derefs(nir_deref_type_array), 2);
1938 ASSERT_EQ(count_function_temp_vars(), 1);
1939
1940 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
1941 EXPECT_TRUE(progress);
1942
1943 nir_validate_shader(b->shader, NULL);
1944 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
1945 /* this pass doesn't remove the unused ones */
1946 ASSERT_EQ(count_function_temp_vars(), 4);
1947 }
1948
1949 TEST_F(nir_split_vars_test, two_level_split)
1950 {
1951 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
1952 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 4, 0), 4, 0),
1953 "temp");
1954 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1955 for (int i = 0; i < 4; i++) {
1956 nir_deref_instr *level0 = nir_build_deref_array_imm(b, temp_deref, i);
1957 for (int j = 0; j < 4; j++) {
1958 nir_deref_instr *level1 = nir_build_deref_array_imm(b, level0, j);
1959 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1);
1960 }
1961 }
1962
1963 nir_validate_shader(b->shader, NULL);
1964 ASSERT_EQ(count_derefs(nir_deref_type_array), 20);
1965 ASSERT_EQ(count_function_temp_vars(), 1);
1966
1967 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
1968 EXPECT_TRUE(progress);
1969
1970 nir_validate_shader(b->shader, NULL);
1971 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
1972 ASSERT_EQ(count_function_temp_vars(), 16);
1973 }
1974
1975 TEST_F(nir_split_vars_test, simple_dont_split)
1976 {
1977 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
1978 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
1979 "temp");
1980 nir_variable *ind = create_int(nir_var_shader_in, "ind");
1981
1982 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind);
1983 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
1984
1985 for (int i = 0; i < 4; i++)
1986 nir_store_deref(b, nir_build_deref_array(b, temp_deref, &ind_deref->dest.ssa), nir_load_var(b, in[i]), 1);
1987
1988 nir_validate_shader(b->shader, NULL);
1989 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
1990 ASSERT_EQ(count_function_temp_vars(), 1);
1991
1992 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
1993 EXPECT_FALSE(progress);
1994
1995 nir_validate_shader(b->shader, NULL);
1996 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
1997 ASSERT_EQ(count_function_temp_vars(), 1);
1998 }
1999
2000 TEST_F(nir_split_vars_test, twolevel_dont_split_lvl_0)
2001 {
2002 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2003 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 6, 0), 4, 0),
2004 "temp");
2005 nir_variable *ind = create_int(nir_var_shader_in, "ind");
2006
2007 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind);
2008 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2009
2010 for (int i = 0; i < 4; i++) {
2011 nir_deref_instr *level0 = nir_build_deref_array(b, temp_deref, &ind_deref->dest.ssa);
2012 for (int j = 0; j < 6; j++) {
2013 nir_deref_instr *level1 = nir_build_deref_array_imm(b, level0, j);
2014 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1);
2015 }
2016 }
2017
2018 nir_validate_shader(b->shader, NULL);
2019 ASSERT_EQ(count_derefs(nir_deref_type_array), 28);
2020 ASSERT_EQ(count_function_temp_vars(), 1);
2021
2022 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2023 EXPECT_TRUE(progress);
2024
2025 nir_validate_shader(b->shader, NULL);
2026 ASSERT_EQ(count_derefs(nir_deref_type_array), 24);
2027 ASSERT_EQ(count_function_temp_vars(), 6);
2028 }
2029
2030 TEST_F(nir_split_vars_test, twolevel_dont_split_lvl_1)
2031 {
2032 nir_variable **in = create_many_int(nir_var_shader_in, "in", 6);
2033 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 6, 0), 4, 0),
2034 "temp");
2035 nir_variable *ind = create_int(nir_var_shader_in, "ind");
2036
2037 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind);
2038 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2039
2040 for (int i = 0; i < 4; i++) {
2041 nir_deref_instr *level0 = nir_build_deref_array_imm(b, temp_deref, i);
2042 for (int j = 0; j < 6; j++) {
2043 /* just add the inner index to get some different derefs */
2044 nir_deref_instr *level1 = nir_build_deref_array(b, level0, nir_iadd(b, &ind_deref->dest.ssa, nir_imm_int(b, j)));
2045 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1);
2046 }
2047 }
2048
2049 nir_validate_shader(b->shader, NULL);
2050 ASSERT_EQ(count_derefs(nir_deref_type_array), 28);
2051 ASSERT_EQ(count_function_temp_vars(), 1);
2052
2053 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2054 EXPECT_TRUE(progress);
2055
2056 nir_validate_shader(b->shader, NULL);
2057 ASSERT_EQ(count_derefs(nir_deref_type_array), 24);
2058 ASSERT_EQ(count_function_temp_vars(), 4);
2059 }
2060
2061 TEST_F(nir_split_vars_test, split_multiple_store)
2062 {
2063 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2064 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2065 "temp");
2066 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2067 "temp2");
2068
2069 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2070 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2071
2072 for (int i = 0; i < 4; i++)
2073 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2074
2075 for (int i = 0; i < 4; i++)
2076 nir_store_deref(b, nir_build_deref_array_imm(b, temp2_deref, i), nir_load_var(b, in[i]), 1);
2077
2078 nir_validate_shader(b->shader, NULL);
2079 ASSERT_EQ(count_derefs(nir_deref_type_array), 8);
2080 ASSERT_EQ(count_function_temp_vars(), 2);
2081
2082 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2083 EXPECT_TRUE(progress);
2084
2085 nir_validate_shader(b->shader, NULL);
2086 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2087 ASSERT_EQ(count_function_temp_vars(), 8);
2088 }
2089
2090 TEST_F(nir_split_vars_test, split_load_store)
2091 {
2092 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2093 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2094 "temp");
2095 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2096 "temp2");
2097
2098 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2099 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2100
2101 for (int i = 0; i < 4; i++)
2102 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2103
2104 for (int i = 0; i < 4; i++) {
2105 nir_deref_instr *store_deref = nir_build_deref_array_imm(b, temp2_deref, i);
2106 nir_deref_instr *load_deref = nir_build_deref_array_imm(b, temp_deref, i);
2107 nir_store_deref(b, store_deref, nir_load_deref(b, load_deref), 1);
2108 }
2109
2110 nir_validate_shader(b->shader, NULL);
2111 ASSERT_EQ(count_derefs(nir_deref_type_array), 12);
2112 ASSERT_EQ(count_function_temp_vars(), 2);
2113
2114 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2115 EXPECT_TRUE(progress);
2116
2117 nir_validate_shader(b->shader, NULL);
2118 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2119 ASSERT_EQ(count_function_temp_vars(), 8);
2120 }
2121
2122 TEST_F(nir_split_vars_test, split_copy)
2123 {
2124 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2125 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2126 "temp");
2127 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2128 "temp2");
2129
2130 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2131 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2132
2133 for (int i = 0; i < 4; i++)
2134 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2135
2136 for (int i = 0; i < 4; i++) {
2137 nir_deref_instr *store_deref = nir_build_deref_array_imm(b, temp2_deref, i);
2138 nir_deref_instr *load_deref = nir_build_deref_array_imm(b, temp_deref, i);
2139 nir_copy_deref(b, store_deref, load_deref);
2140 }
2141
2142 nir_validate_shader(b->shader, NULL);
2143 ASSERT_EQ(count_derefs(nir_deref_type_array), 12);
2144 ASSERT_EQ(count_function_temp_vars(), 2);
2145
2146 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2147 EXPECT_TRUE(progress);
2148
2149 nir_validate_shader(b->shader, NULL);
2150 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2151 ASSERT_EQ(count_function_temp_vars(), 8);
2152 }
2153
2154 TEST_F(nir_split_vars_test, split_wildcard_copy)
2155 {
2156 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4);
2157 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2158 "temp");
2159 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0),
2160 "temp2");
2161
2162 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp);
2163 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2);
2164
2165 for (int i = 0; i < 4; i++)
2166 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1);
2167
2168 nir_deref_instr *src_wildcard = nir_build_deref_array_wildcard(b, temp_deref);
2169 nir_deref_instr *dst_wildcard = nir_build_deref_array_wildcard(b, temp2_deref);
2170
2171 nir_copy_deref(b, dst_wildcard, src_wildcard);
2172
2173 nir_validate_shader(b->shader, NULL);
2174 ASSERT_EQ(count_derefs(nir_deref_type_array), 4);
2175 ASSERT_EQ(count_derefs(nir_deref_type_array_wildcard), 2);
2176 ASSERT_EQ(count_function_temp_vars(), 2);
2177 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 1);
2178
2179 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp);
2180 EXPECT_TRUE(progress);
2181
2182 nir_validate_shader(b->shader, NULL);
2183 ASSERT_EQ(count_derefs(nir_deref_type_array), 0);
2184 ASSERT_EQ(count_derefs(nir_deref_type_array_wildcard), 0);
2185 ASSERT_EQ(count_function_temp_vars(), 8);
2186 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 4);
2187 }