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