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
29namespace {
30
31class nir_vars_test : public ::testing::Test {
32protected:
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_intrinsics(nir_intrinsic_op intrinsic);
78
79   nir_intrinsic_instr *get_intrinsic(nir_intrinsic_op intrinsic,
80                                      unsigned index);
81
82   void *mem_ctx;
83   void *lin_ctx;
84
85   nir_builder *b;
86};
87
88nir_vars_test::nir_vars_test()
89{
90   mem_ctx = ralloc_context(NULL);
91   lin_ctx = linear_alloc_parent(mem_ctx, 0);
92   static const nir_shader_compiler_options options = { };
93   b = rzalloc(mem_ctx, nir_builder);
94   nir_builder_init_simple_shader(b, mem_ctx, MESA_SHADER_FRAGMENT, &options);
95}
96
97nir_vars_test::~nir_vars_test()
98{
99   if (HasFailure()) {
100      printf("\nShader from the failed test:\n\n");
101      nir_print_shader(b->shader, stdout);
102   }
103
104   ralloc_free(mem_ctx);
105}
106
107unsigned
108nir_vars_test::count_intrinsics(nir_intrinsic_op intrinsic)
109{
110   unsigned count = 0;
111   nir_foreach_block(block, b->impl) {
112      nir_foreach_instr(instr, block) {
113         if (instr->type != nir_instr_type_intrinsic)
114            continue;
115         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
116         if (intrin->intrinsic == intrinsic)
117            count++;
118      }
119   }
120   return count;
121}
122
123nir_intrinsic_instr *
124nir_vars_test::get_intrinsic(nir_intrinsic_op intrinsic,
125                             unsigned index)
126{
127   nir_foreach_block(block, b->impl) {
128      nir_foreach_instr(instr, block) {
129         if (instr->type != nir_instr_type_intrinsic)
130            continue;
131         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
132         if (intrin->intrinsic == intrinsic) {
133            if (index == 0)
134               return intrin;
135            index--;
136         }
137      }
138   }
139   return NULL;
140}
141
142/* Allow grouping the tests while still sharing the helpers. */
143class nir_redundant_load_vars_test : public nir_vars_test {};
144class nir_copy_prop_vars_test : public nir_vars_test {};
145class nir_dead_write_vars_test : public nir_vars_test {};
146class nir_combine_stores_test : public nir_vars_test {};
147
148} // namespace
149
150TEST_F(nir_redundant_load_vars_test, duplicated_load)
151{
152   /* Load a variable twice in the same block.  One should be removed. */
153
154   nir_variable *in = create_int(nir_var_shader_in, "in");
155   nir_variable **out = create_many_int(nir_var_shader_out, "out", 2);
156
157   nir_store_var(b, out[0], nir_load_var(b, in), 1);
158   nir_store_var(b, out[1], nir_load_var(b, in), 1);
159
160   nir_validate_shader(b->shader, NULL);
161
162   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
163
164   bool progress = nir_opt_copy_prop_vars(b->shader);
165   EXPECT_TRUE(progress);
166
167   nir_validate_shader(b->shader, NULL);
168
169   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
170}
171
172TEST_F(nir_redundant_load_vars_test, duplicated_load_in_two_blocks)
173{
174   /* Load a variable twice in different blocks.  One should be removed. */
175
176   nir_variable *in = create_int(nir_var_shader_in, "in");
177   nir_variable **out = create_many_int(nir_var_shader_out, "out", 2);
178
179   nir_store_var(b, out[0], nir_load_var(b, in), 1);
180
181   /* Forces the stores to be in different blocks. */
182   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
183
184   nir_store_var(b, out[1], nir_load_var(b, in), 1);
185
186   nir_validate_shader(b->shader, NULL);
187
188   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
189
190   bool progress = nir_opt_copy_prop_vars(b->shader);
191   EXPECT_TRUE(progress);
192
193   nir_validate_shader(b->shader, NULL);
194
195   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
196}
197
198TEST_F(nir_redundant_load_vars_test, invalidate_inside_if_block)
199{
200   /* Load variables, then write to some of then in different branches of the
201    * if statement.  They should be invalidated accordingly.
202    */
203
204   nir_variable **g = create_many_int(nir_var_shader_temp, "g", 3);
205   nir_variable **out = create_many_int(nir_var_shader_out, "out", 3);
206
207   nir_load_var(b, g[0]);
208   nir_load_var(b, g[1]);
209   nir_load_var(b, g[2]);
210
211   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
212   nir_store_var(b, g[0], nir_imm_int(b, 10), 1);
213
214   nir_push_else(b, if_stmt);
215   nir_store_var(b, g[1], nir_imm_int(b, 20), 1);
216
217   nir_pop_if(b, if_stmt);
218
219   nir_store_var(b, out[0], nir_load_var(b, g[0]), 1);
220   nir_store_var(b, out[1], nir_load_var(b, g[1]), 1);
221   nir_store_var(b, out[2], nir_load_var(b, g[2]), 1);
222
223   nir_validate_shader(b->shader, NULL);
224
225   bool progress = nir_opt_copy_prop_vars(b->shader);
226   EXPECT_TRUE(progress);
227
228   /* There are 3 initial loads, plus 2 loads for the values invalidated
229    * inside the if statement.
230    */
231   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 5);
232
233   /* We only load g[2] once. */
234   unsigned g2_load_count = 0;
235   for (int i = 0; i < 5; i++) {
236         nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, i);
237         if (nir_intrinsic_get_var(load, 0) == g[2])
238            g2_load_count++;
239   }
240   EXPECT_EQ(g2_load_count, 1);
241}
242
243TEST_F(nir_redundant_load_vars_test, invalidate_live_load_in_the_end_of_loop)
244{
245   /* Invalidating a load in the end of loop body will apply to the whole loop
246    * body.
247    */
248
249   nir_variable *v = create_int(nir_var_mem_ssbo, "v");
250
251   nir_load_var(b, v);
252
253   nir_loop *loop = nir_push_loop(b);
254
255   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
256   nir_jump(b, nir_jump_break);
257   nir_pop_if(b, if_stmt);
258
259   nir_load_var(b, v);
260   nir_store_var(b, v, nir_imm_int(b, 10), 1);
261
262   nir_pop_loop(b, loop);
263
264   bool progress = nir_opt_copy_prop_vars(b->shader);
265   ASSERT_FALSE(progress);
266}
267
268TEST_F(nir_copy_prop_vars_test, simple_copies)
269{
270   nir_variable *in   = create_int(nir_var_shader_in,     "in");
271   nir_variable *temp = create_int(nir_var_function_temp, "temp");
272   nir_variable *out  = create_int(nir_var_shader_out,    "out");
273
274   nir_copy_var(b, temp, in);
275   nir_copy_var(b, out, temp);
276
277   nir_validate_shader(b->shader, NULL);
278
279   bool progress = nir_opt_copy_prop_vars(b->shader);
280   EXPECT_TRUE(progress);
281
282   nir_validate_shader(b->shader, NULL);
283
284   ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 2);
285
286   nir_intrinsic_instr *first_copy = get_intrinsic(nir_intrinsic_copy_deref, 0);
287   ASSERT_TRUE(first_copy->src[1].is_ssa);
288
289   nir_intrinsic_instr *second_copy = get_intrinsic(nir_intrinsic_copy_deref, 1);
290   ASSERT_TRUE(second_copy->src[1].is_ssa);
291
292   EXPECT_EQ(first_copy->src[1].ssa, second_copy->src[1].ssa);
293}
294
295TEST_F(nir_copy_prop_vars_test, simple_store_load)
296{
297   nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
298   unsigned mask = 1 | 2;
299
300   nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20);
301   nir_store_var(b, v[0], stored_value, mask);
302
303   nir_ssa_def *read_value = nir_load_var(b, v[0]);
304   nir_store_var(b, v[1], read_value, mask);
305
306   nir_validate_shader(b->shader, NULL);
307
308   bool progress = nir_opt_copy_prop_vars(b->shader);
309   EXPECT_TRUE(progress);
310
311   nir_validate_shader(b->shader, NULL);
312
313   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
314
315   for (int i = 0; i < 2; i++) {
316      nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i);
317      ASSERT_TRUE(store->src[1].is_ssa);
318      EXPECT_EQ(store->src[1].ssa, stored_value);
319   }
320}
321
322TEST_F(nir_copy_prop_vars_test, store_store_load)
323{
324   nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
325   unsigned mask = 1 | 2;
326
327   nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
328   nir_store_var(b, v[0], first_value, mask);
329
330   nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
331   nir_store_var(b, v[0], second_value, mask);
332
333   nir_ssa_def *read_value = nir_load_var(b, v[0]);
334   nir_store_var(b, v[1], read_value, mask);
335
336   nir_validate_shader(b->shader, NULL);
337
338   bool progress = nir_opt_copy_prop_vars(b->shader);
339   EXPECT_TRUE(progress);
340
341   nir_validate_shader(b->shader, NULL);
342
343   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
344
345   /* Store to v[1] should use second_value directly. */
346   nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2);
347   ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
348   ASSERT_TRUE(store_to_v1->src[1].is_ssa);
349   EXPECT_EQ(store_to_v1->src[1].ssa, second_value);
350}
351
352TEST_F(nir_copy_prop_vars_test, store_store_load_different_components)
353{
354   nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
355
356   nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
357   nir_store_var(b, v[0], first_value, 1 << 1);
358
359   nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
360   nir_store_var(b, v[0], second_value, 1 << 0);
361
362   nir_ssa_def *read_value = nir_load_var(b, v[0]);
363   nir_store_var(b, v[1], read_value, 1 << 1);
364
365   nir_validate_shader(b->shader, NULL);
366
367   bool progress = nir_opt_copy_prop_vars(b->shader);
368   EXPECT_TRUE(progress);
369
370   nir_validate_shader(b->shader, NULL);
371
372   nir_opt_constant_folding(b->shader);
373   nir_validate_shader(b->shader, NULL);
374
375   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
376
377   /* Store to v[1] should use first_value directly.  The write of
378    * second_value did not overwrite the component it uses.
379    */
380   nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2);
381   ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
382   ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20);
383}
384
385TEST_F(nir_copy_prop_vars_test, store_store_load_different_components_in_many_blocks)
386{
387   nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
388
389   nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20);
390   nir_store_var(b, v[0], first_value, 1 << 1);
391
392   /* Adding an if statement will cause blocks to be created. */
393   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
394
395   nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40);
396   nir_store_var(b, v[0], second_value, 1 << 0);
397
398   /* Adding an if statement will cause blocks to be created. */
399   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
400
401   nir_ssa_def *read_value = nir_load_var(b, v[0]);
402   nir_store_var(b, v[1], read_value, 1 << 1);
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   nir_opt_constant_folding(b->shader);
412   nir_validate_shader(b->shader, NULL);
413
414   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
415
416   /* Store to v[1] should use first_value directly.  The write of
417    * second_value did not overwrite the component it uses.
418    */
419   nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2);
420   ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]);
421   ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20);
422}
423
424TEST_F(nir_copy_prop_vars_test, memory_barrier_in_two_blocks)
425{
426   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 4);
427
428   nir_store_var(b, v[0], nir_imm_int(b, 1), 1);
429   nir_store_var(b, v[1], nir_imm_int(b, 2), 1);
430
431   /* Split into many blocks. */
432   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
433
434   nir_store_var(b, v[2], nir_load_var(b, v[0]), 1);
435
436   nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_memory_barrier)->instr);
437
438   nir_store_var(b, v[3], nir_load_var(b, v[1]), 1);
439
440   bool progress = nir_opt_copy_prop_vars(b->shader);
441   ASSERT_TRUE(progress);
442
443   /* Only the second load will remain after the optimization. */
444   ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref));
445   nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0);
446   ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[1]);
447}
448
449TEST_F(nir_copy_prop_vars_test, simple_store_load_in_two_blocks)
450{
451   nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2);
452   unsigned mask = 1 | 2;
453
454   nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20);
455   nir_store_var(b, v[0], stored_value, mask);
456
457   /* Adding an if statement will cause blocks to be created. */
458   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
459
460   nir_ssa_def *read_value = nir_load_var(b, v[0]);
461   nir_store_var(b, v[1], read_value, mask);
462
463   nir_validate_shader(b->shader, NULL);
464
465   bool progress = nir_opt_copy_prop_vars(b->shader);
466   EXPECT_TRUE(progress);
467
468   nir_validate_shader(b->shader, NULL);
469
470   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
471
472   for (int i = 0; i < 2; i++) {
473      nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i);
474      ASSERT_TRUE(store->src[1].is_ssa);
475      EXPECT_EQ(store->src[1].ssa, stored_value);
476   }
477}
478
479TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_load)
480{
481   nir_variable *in0 = create_ivec2(nir_var_mem_ssbo, "in0");
482   nir_variable *in1 = create_ivec2(nir_var_mem_ssbo, "in1");
483   nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
484   nir_variable *out = create_int(nir_var_mem_ssbo, "out");
485
486   nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0);
487   nir_store_var(b, vec, nir_load_var(b, in1), 1 << 1);
488
489   /* This load will be dropped, as vec.y (or vec[1]) is already known. */
490   nir_deref_instr *deref =
491      nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
492   nir_ssa_def *loaded_from_deref = nir_load_deref(b, deref);
493
494   /* This store should use the value loaded from in1. */
495   nir_store_var(b, out, loaded_from_deref, 1 << 0);
496
497   nir_validate_shader(b->shader, NULL);
498   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
499   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
500
501   bool progress = nir_opt_copy_prop_vars(b->shader);
502   EXPECT_TRUE(progress);
503
504   nir_validate_shader(b->shader, NULL);
505   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
506   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
507
508   nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 2);
509   ASSERT_TRUE(store->src[1].is_ssa);
510
511   /* NOTE: The ALU instruction is how we get the vec.y. */
512   ASSERT_TRUE(nir_src_as_alu_instr(store->src[1]));
513}
514
515TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_copy)
516{
517   nir_variable *in0 = create_ivec2(nir_var_mem_ssbo, "in0");
518   nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
519
520   nir_copy_var(b, vec, in0);
521
522   /* This load will be replaced with one from in0. */
523   nir_deref_instr *deref =
524      nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
525   nir_load_deref(b, deref);
526
527   nir_validate_shader(b->shader, NULL);
528
529   bool progress = nir_opt_copy_prop_vars(b->shader);
530   EXPECT_TRUE(progress);
531
532   nir_validate_shader(b->shader, NULL);
533   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
534
535   nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0);
536   ASSERT_EQ(nir_intrinsic_get_var(load, 0), in0);
537}
538
539TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_gets_reused)
540{
541   nir_variable *in0 = create_ivec2(nir_var_mem_ssbo, "in0");
542   nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
543   nir_variable *out = create_ivec2(nir_var_mem_ssbo, "out");
544
545   /* Loading "vec[1]" deref will save the information about vec.y. */
546   nir_deref_instr *deref =
547      nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
548   nir_load_deref(b, deref);
549
550   /* Store to vec.x. */
551   nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0);
552
553   /* This load will be dropped, since both vec.x and vec.y are known. */
554   nir_ssa_def *loaded_from_vec = nir_load_var(b, vec);
555   nir_store_var(b, out, loaded_from_vec, 0x3);
556
557   nir_validate_shader(b->shader, NULL);
558   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
559   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
560
561   bool progress = nir_opt_copy_prop_vars(b->shader);
562   EXPECT_TRUE(progress);
563
564   nir_validate_shader(b->shader, NULL);
565   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
566   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
567
568   nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 1);
569   ASSERT_TRUE(store->src[1].is_ssa);
570   ASSERT_TRUE(nir_src_as_alu_instr(store->src[1]));
571}
572
573TEST_F(nir_copy_prop_vars_test, store_load_direct_array_deref_on_vector)
574{
575   nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
576   nir_variable *out0 = create_int(nir_var_mem_ssbo, "out0");
577   nir_variable *out1 = create_ivec2(nir_var_mem_ssbo, "out1");
578
579   /* Store to "vec[1]" and "vec[0]". */
580   nir_deref_instr *store_deref_y =
581      nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
582   nir_store_deref(b, store_deref_y, nir_imm_int(b, 20), 1);
583
584   nir_deref_instr *store_deref_x =
585      nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 0);
586   nir_store_deref(b, store_deref_x, nir_imm_int(b, 10), 1);
587
588   /* Both loads below will be dropped, because the values are already known. */
589   nir_deref_instr *load_deref_y =
590      nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1);
591   nir_store_var(b, out0, nir_load_deref(b, load_deref_y), 1);
592
593   nir_store_var(b, out1, nir_load_var(b, vec), 1);
594
595   nir_validate_shader(b->shader, NULL);
596   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
597   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4);
598
599   bool progress = nir_opt_copy_prop_vars(b->shader);
600   EXPECT_TRUE(progress);
601
602   nir_validate_shader(b->shader, NULL);
603   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0);
604   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4);
605
606   /* Third store will just use the value from first store. */
607   nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
608   nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2);
609   ASSERT_TRUE(third_store->src[1].is_ssa);
610   EXPECT_EQ(third_store->src[1].ssa, first_store->src[1].ssa);
611
612   /* Fourth store will compose first and second store values. */
613   nir_intrinsic_instr *fourth_store = get_intrinsic(nir_intrinsic_store_deref, 3);
614   ASSERT_TRUE(fourth_store->src[1].is_ssa);
615   EXPECT_TRUE(nir_src_as_alu_instr(fourth_store->src[1]));
616}
617
618TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref_on_vector)
619{
620   nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
621   nir_variable *idx = create_int(nir_var_mem_ssbo, "idx");
622   nir_variable *out = create_int(nir_var_mem_ssbo, "out");
623
624   nir_ssa_def *idx_ssa = nir_load_var(b, idx);
625
626   /* Store to vec[idx]. */
627   nir_deref_instr *store_deref =
628      nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa);
629   nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1);
630
631   /* Load from vec[idx] to store in out. This load should be dropped. */
632   nir_deref_instr *load_deref =
633      nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa);
634   nir_store_var(b, out, nir_load_deref(b, load_deref), 1);
635
636   nir_validate_shader(b->shader, NULL);
637   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
638   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
639
640   bool progress = nir_opt_copy_prop_vars(b->shader);
641   EXPECT_TRUE(progress);
642
643   nir_validate_shader(b->shader, NULL);
644   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
645   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
646
647   /* Store to vec[idx] propagated to out. */
648   nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
649   nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
650   ASSERT_TRUE(first->src[1].is_ssa);
651   ASSERT_TRUE(second->src[1].is_ssa);
652   EXPECT_EQ(first->src[1].ssa, second->src[1].ssa);
653}
654
655TEST_F(nir_copy_prop_vars_test, store_load_direct_and_indirect_array_deref_on_vector)
656{
657   nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec");
658   nir_variable *idx = create_int(nir_var_mem_ssbo, "idx");
659   nir_variable **out = create_many_int(nir_var_mem_ssbo, "out", 2);
660
661   nir_ssa_def *idx_ssa = nir_load_var(b, idx);
662
663   /* Store to vec. */
664   nir_store_var(b, vec, nir_imm_ivec2(b, 10, 10), 1 | 2);
665
666   /* Load from vec[idx]. This load is currently not dropped. */
667   nir_deref_instr *indirect =
668      nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa);
669   nir_store_var(b, out[0], nir_load_deref(b, indirect), 1);
670
671   /* Load from vec[idx] again. This load should be dropped. */
672   nir_store_var(b, out[1], nir_load_deref(b, indirect), 1);
673
674   nir_validate_shader(b->shader, NULL);
675   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3);
676   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
677
678   bool progress = nir_opt_copy_prop_vars(b->shader);
679   EXPECT_TRUE(progress);
680
681   nir_validate_shader(b->shader, NULL);
682   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
683   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3);
684
685   /* Store to vec[idx] propagated to out. */
686   nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
687   nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2);
688   ASSERT_TRUE(second->src[1].is_ssa);
689   ASSERT_TRUE(third->src[1].is_ssa);
690   EXPECT_EQ(second->src[1].ssa, third->src[1].ssa);
691}
692
693TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref)
694{
695   nir_variable *arr = create_var(nir_var_mem_ssbo,
696                                  glsl_array_type(glsl_int_type(), 10, 0),
697                                  "arr");
698   nir_variable *idx = create_int(nir_var_mem_ssbo, "idx");
699   nir_variable *out = create_int(nir_var_mem_ssbo, "out");
700
701   nir_ssa_def *idx_ssa = nir_load_var(b, idx);
702
703   /* Store to arr[idx]. */
704   nir_deref_instr *store_deref =
705      nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa);
706   nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1);
707
708   /* Load from arr[idx] to store in out. This load should be dropped. */
709   nir_deref_instr *load_deref =
710      nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa);
711   nir_store_var(b, out, nir_load_deref(b, load_deref), 1);
712
713   nir_validate_shader(b->shader, NULL);
714   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2);
715   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
716
717   bool progress = nir_opt_copy_prop_vars(b->shader);
718   EXPECT_TRUE(progress);
719
720   nir_validate_shader(b->shader, NULL);
721   ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1);
722   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2);
723
724   /* Store to arr[idx] propagated to out. */
725   nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0);
726   nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1);
727   ASSERT_TRUE(first->src[1].is_ssa);
728   ASSERT_TRUE(second->src[1].is_ssa);
729   EXPECT_EQ(first->src[1].ssa, second->src[1].ssa);
730}
731
732TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block)
733{
734   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2);
735
736   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
737
738   bool progress = nir_opt_dead_write_vars(b->shader);
739   ASSERT_FALSE(progress);
740}
741
742TEST_F(nir_dead_write_vars_test, no_dead_writes_different_components_in_block)
743{
744   nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3);
745
746   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
747   nir_store_var(b, v[0], nir_load_var(b, v[2]), 1 << 1);
748
749   bool progress = nir_opt_dead_write_vars(b->shader);
750   ASSERT_FALSE(progress);
751}
752
753TEST_F(nir_dead_write_vars_test, no_dead_writes_in_if_statement)
754{
755   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 6);
756
757   nir_store_var(b, v[2], nir_load_var(b, v[0]), 1);
758   nir_store_var(b, v[3], nir_load_var(b, v[1]), 1);
759
760   /* Each arm of the if statement will overwrite one store. */
761   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
762   nir_store_var(b, v[2], nir_load_var(b, v[4]), 1);
763
764   nir_push_else(b, if_stmt);
765   nir_store_var(b, v[3], nir_load_var(b, v[5]), 1);
766
767   nir_pop_if(b, if_stmt);
768
769   bool progress = nir_opt_dead_write_vars(b->shader);
770   ASSERT_FALSE(progress);
771}
772
773TEST_F(nir_dead_write_vars_test, no_dead_writes_in_loop_statement)
774{
775   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
776
777   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
778
779   /* Loop will write other value.  Since it might not be executed, it doesn't
780    * kill the first write.
781    */
782   nir_loop *loop = nir_push_loop(b);
783
784   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
785   nir_jump(b, nir_jump_break);
786   nir_pop_if(b, if_stmt);
787
788   nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
789   nir_pop_loop(b, loop);
790
791   bool progress = nir_opt_dead_write_vars(b->shader);
792   ASSERT_FALSE(progress);
793}
794
795TEST_F(nir_dead_write_vars_test, dead_write_in_block)
796{
797   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
798
799   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
800   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
801   nir_store_var(b, v[0], load_v2, 1);
802
803   bool progress = nir_opt_dead_write_vars(b->shader);
804   ASSERT_TRUE(progress);
805
806   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
807
808   nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
809   ASSERT_TRUE(store->src[1].is_ssa);
810   EXPECT_EQ(store->src[1].ssa, load_v2);
811}
812
813TEST_F(nir_dead_write_vars_test, dead_write_components_in_block)
814{
815   nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3);
816
817   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
818   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
819   nir_store_var(b, v[0], load_v2, 1 << 0);
820
821   bool progress = nir_opt_dead_write_vars(b->shader);
822   ASSERT_TRUE(progress);
823
824   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
825
826   nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
827   ASSERT_TRUE(store->src[1].is_ssa);
828   EXPECT_EQ(store->src[1].ssa, load_v2);
829}
830
831
832/* TODO: The DISABLED tests below depend on the dead write removal be able to
833 * identify dead writes between multiple blocks.  This is still not
834 * implemented.
835 */
836
837TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_in_two_blocks)
838{
839   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
840
841   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
842   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
843
844   /* Causes the stores to be in different blocks. */
845   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
846
847   nir_store_var(b, v[0], load_v2, 1);
848
849   bool progress = nir_opt_dead_write_vars(b->shader);
850   ASSERT_TRUE(progress);
851
852   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
853
854   nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
855   ASSERT_TRUE(store->src[1].is_ssa);
856   EXPECT_EQ(store->src[1].ssa, load_v2);
857}
858
859TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_components_in_two_blocks)
860{
861   nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3);
862
863   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0);
864
865   /* Causes the stores to be in different blocks. */
866   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
867
868   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
869   nir_store_var(b, v[0], load_v2, 1 << 0);
870
871   bool progress = nir_opt_dead_write_vars(b->shader);
872   ASSERT_TRUE(progress);
873
874   EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref));
875
876   nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0);
877   ASSERT_TRUE(store->src[1].is_ssa);
878   EXPECT_EQ(store->src[1].ssa, load_v2);
879}
880
881TEST_F(nir_dead_write_vars_test, DISABLED_dead_writes_in_if_statement)
882{
883   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 4);
884
885   /* Both branches will overwrite, making the previous store dead. */
886   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
887
888   nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0));
889   nir_ssa_def *load_v2 = nir_load_var(b, v[2]);
890   nir_store_var(b, v[0], load_v2, 1);
891
892   nir_push_else(b, if_stmt);
893   nir_ssa_def *load_v3 = nir_load_var(b, v[3]);
894   nir_store_var(b, v[0], load_v3, 1);
895
896   nir_pop_if(b, if_stmt);
897
898   bool progress = nir_opt_dead_write_vars(b->shader);
899   ASSERT_TRUE(progress);
900   EXPECT_EQ(2, count_intrinsics(nir_intrinsic_store_deref));
901
902   nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
903   ASSERT_TRUE(first_store->src[1].is_ssa);
904   EXPECT_EQ(first_store->src[1].ssa, load_v2);
905
906   nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1);
907   ASSERT_TRUE(second_store->src[1].is_ssa);
908   EXPECT_EQ(second_store->src[1].ssa, load_v3);
909}
910
911TEST_F(nir_dead_write_vars_test, DISABLED_memory_barrier_in_two_blocks)
912{
913   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2);
914
915   nir_store_var(b, v[0], nir_imm_int(b, 1), 1);
916   nir_store_var(b, v[1], nir_imm_int(b, 2), 1);
917
918   /* Split into many blocks. */
919   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
920
921   /* Because it is before the barrier, this will kill the previous store to that target. */
922   nir_store_var(b, v[0], nir_imm_int(b, 3), 1);
923
924   nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_memory_barrier)->instr);
925
926   nir_store_var(b, v[1], nir_imm_int(b, 4), 1);
927
928   bool progress = nir_opt_dead_write_vars(b->shader);
929   ASSERT_TRUE(progress);
930
931   EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
932}
933
934TEST_F(nir_dead_write_vars_test, DISABLED_unrelated_barrier_in_two_blocks)
935{
936   nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3);
937   nir_variable *out = create_int(nir_var_shader_out, "out");
938
939   nir_store_var(b, out, nir_load_var(b, v[1]), 1);
940   nir_store_var(b, v[0], nir_load_var(b, v[1]), 1);
941
942   /* Split into many blocks. */
943   nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0)));
944
945   /* Emit vertex will ensure writes to output variables are considered used,
946    * but should not affect other types of variables. */
947
948   nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_emit_vertex)->instr);
949
950   nir_store_var(b, out, nir_load_var(b, v[2]), 1);
951   nir_store_var(b, v[0], nir_load_var(b, v[2]), 1);
952
953   bool progress = nir_opt_dead_write_vars(b->shader);
954   ASSERT_TRUE(progress);
955
956   /* Verify the first write to v[0] was removed. */
957   EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref));
958
959   nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0);
960   EXPECT_EQ(nir_intrinsic_get_var(first_store, 0), out);
961
962   nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1);
963   EXPECT_EQ(nir_intrinsic_get_var(second_store, 0), out);
964
965   nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2);
966   EXPECT_EQ(nir_intrinsic_get_var(third_store, 0), v[0]);
967}
968
969TEST_F(nir_combine_stores_test, non_overlapping_stores)
970{
971   nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "v", 4);
972   nir_variable *out = create_ivec4(nir_var_shader_out, "out");
973
974   for (int i = 0; i < 4; i++)
975      nir_store_var(b, out, nir_load_var(b, v[i]), 1 << i);
976
977   nir_validate_shader(b->shader, NULL);
978
979   bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
980   ASSERT_TRUE(progress);
981
982   nir_validate_shader(b->shader, NULL);
983
984   /* Clean up to verify from where the values in combined store are coming. */
985   nir_copy_prop(b->shader);
986   nir_opt_dce(b->shader);
987
988   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
989   nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
990   ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
991   ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
992
993   nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
994   ASSERT_TRUE(vec);
995   for (int i = 0; i < 4; i++) {
996      nir_intrinsic_instr *load = nir_src_as_intrinsic(vec->src[i].src);
997      ASSERT_EQ(load->intrinsic, nir_intrinsic_load_deref);
998      ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[i])
999         << "Source value for component " << i << " of store is wrong";
1000      ASSERT_EQ(vec->src[i].swizzle[0], i)
1001         << "Source component for component " << i << " of store is wrong";
1002   }
1003}
1004
1005TEST_F(nir_combine_stores_test, overlapping_stores)
1006{
1007   nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "v", 3);
1008   nir_variable *out = create_ivec4(nir_var_shader_out, "out");
1009
1010   /* Make stores with xy, yz and zw masks. */
1011   for (int i = 0; i < 3; i++) {
1012      nir_component_mask_t mask = (1 << i) | (1 << (i + 1));
1013      nir_store_var(b, out, nir_load_var(b, v[i]), mask);
1014   }
1015
1016   nir_validate_shader(b->shader, NULL);
1017
1018   bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out);
1019   ASSERT_TRUE(progress);
1020
1021   nir_validate_shader(b->shader, NULL);
1022
1023   /* Clean up to verify from where the values in combined store are coming. */
1024   nir_copy_prop(b->shader);
1025   nir_opt_dce(b->shader);
1026
1027   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1028   nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1029   ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1030   ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1031
1032   nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1033   ASSERT_TRUE(vec);
1034
1035   /* Component x comes from v[0]. */
1036   nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src);
1037   ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]);
1038   ASSERT_EQ(vec->src[0].swizzle[0], 0);
1039
1040   /* Component y comes from v[1]. */
1041   nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src);
1042   ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]);
1043   ASSERT_EQ(vec->src[1].swizzle[0], 1);
1044
1045   /* Components z and w come from v[2]. */
1046   nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src);
1047   nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src);
1048   ASSERT_EQ(load_for_z, load_for_w);
1049   ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), v[2]);
1050   ASSERT_EQ(vec->src[2].swizzle[0], 2);
1051   ASSERT_EQ(vec->src[3].swizzle[0], 3);
1052}
1053
1054TEST_F(nir_combine_stores_test, direct_array_derefs)
1055{
1056   nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "vec", 2);
1057   nir_variable **s = create_many_int(nir_var_mem_ssbo, "scalar", 2);
1058   nir_variable *out = create_ivec4(nir_var_mem_ssbo, "out");
1059
1060   nir_deref_instr *out_deref = nir_build_deref_var(b, out);
1061
1062   /* Store to vector with mask x. */
1063   nir_store_deref(b, out_deref, nir_load_var(b, v[0]),
1064                   1 << 0);
1065
1066   /* Store to vector with mask yz. */
1067   nir_store_deref(b, out_deref, nir_load_var(b, v[1]),
1068                   (1 << 2) | (1 << 1));
1069
1070   /* Store to vector[2], overlapping with previous store. */
1071   nir_store_deref(b,
1072                   nir_build_deref_array_imm(b, out_deref, 2),
1073                   nir_load_var(b, s[0]),
1074                   1 << 0);
1075
1076   /* Store to vector[3], no overlap. */
1077   nir_store_deref(b,
1078                   nir_build_deref_array_imm(b, out_deref, 3),
1079                   nir_load_var(b, s[1]),
1080                   1 << 0);
1081
1082   nir_validate_shader(b->shader, NULL);
1083
1084   bool progress = nir_opt_combine_stores(b->shader, nir_var_mem_ssbo);
1085   ASSERT_TRUE(progress);
1086
1087   nir_validate_shader(b->shader, NULL);
1088
1089   /* Clean up to verify from where the values in combined store are coming. */
1090   nir_copy_prop(b->shader);
1091   nir_opt_dce(b->shader);
1092
1093   ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1);
1094   nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0);
1095   ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf);
1096   ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out);
1097
1098   nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]);
1099   ASSERT_TRUE(vec);
1100
1101   /* Component x comes from v[0]. */
1102   nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src);
1103   ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]);
1104   ASSERT_EQ(vec->src[0].swizzle[0], 0);
1105
1106   /* Component y comes from v[1]. */
1107   nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src);
1108   ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]);
1109   ASSERT_EQ(vec->src[1].swizzle[0], 1);
1110
1111   /* Components z comes from s[0]. */
1112   nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src);
1113   ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), s[0]);
1114   ASSERT_EQ(vec->src[2].swizzle[0], 0);
1115
1116   /* Component w comes from s[1]. */
1117   nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src);
1118   ASSERT_EQ(nir_intrinsic_get_var(load_for_w, 0), s[1]);
1119   ASSERT_EQ(vec->src[3].swizzle[0], 0);
1120}
1121