• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 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 #include <gtest/gtest.h>
24 #include "ir.h"
25 #include "ir_array_refcount.h"
26 #include "ir_builder.h"
27 #include "util/hash_table.h"
28 
29 using namespace ir_builder;
30 
31 class array_refcount_test : public ::testing::Test {
32 public:
33    virtual void SetUp();
34    virtual void TearDown();
35 
36    exec_list instructions;
37    ir_factory *body;
38    void *mem_ctx;
39 
40    /**
41     * glsl_type for a vec4[3][4][5].
42     *
43     * The exceptionally verbose name is picked because it matches the syntax
44     * of http://cdecl.org/.
45     */
46    const glsl_type *array_3_of_array_4_of_array_5_of_vec4;
47 
48    /**
49     * glsl_type for a int[3].
50     *
51     * The exceptionally verbose name is picked because it matches the syntax
52     * of http://cdecl.org/.
53     */
54    const glsl_type *array_3_of_int;
55 
56    /**
57     * Wrapper to access private member "bits" of ir_array_refcount_entry
58     *
59     * The test class is a friend to ir_array_refcount_entry, but the
60     * individual tests are not part of the class.  Since the friendliness of
61     * the test class does not extend to the tests, provide a wrapper.
62     */
get_bits(const ir_array_refcount_entry & entry)63    const BITSET_WORD *get_bits(const ir_array_refcount_entry &entry)
64    {
65       return entry.bits;
66    }
67 
68    /**
69     * Wrapper to access private member "num_bits" of ir_array_refcount_entry
70     *
71     * The test class is a friend to ir_array_refcount_entry, but the
72     * individual tests are not part of the class.  Since the friendliness of
73     * the test class does not extend to the tests, provide a wrapper.
74     */
get_num_bits(const ir_array_refcount_entry & entry)75    unsigned get_num_bits(const ir_array_refcount_entry &entry)
76    {
77       return entry.num_bits;
78    }
79 
80    /**
81     * Wrapper to access private member "array_depth" of ir_array_refcount_entry
82     *
83     * The test class is a friend to ir_array_refcount_entry, but the
84     * individual tests are not part of the class.  Since the friendliness of
85     * the test class does not extend to the tests, provide a wrapper.
86     */
get_array_depth(const ir_array_refcount_entry & entry)87    unsigned get_array_depth(const ir_array_refcount_entry &entry)
88    {
89       return entry.array_depth;
90    }
91 };
92 
93 void
SetUp()94 array_refcount_test::SetUp()
95 {
96    mem_ctx = ralloc_context(NULL);
97 
98    instructions.make_empty();
99    body = new ir_factory(&instructions, mem_ctx);
100 
101    /* The type of vec4 x[3][4][5]; */
102    const glsl_type *const array_5_of_vec4 =
103       glsl_type::get_array_instance(glsl_type::vec4_type, 5);
104    const glsl_type *const array_4_of_array_5_of_vec4 =
105       glsl_type::get_array_instance(array_5_of_vec4, 4);
106    array_3_of_array_4_of_array_5_of_vec4 =
107       glsl_type::get_array_instance(array_4_of_array_5_of_vec4, 3);
108 
109    array_3_of_int = glsl_type::get_array_instance(glsl_type::int_type, 3);
110 }
111 
112 void
TearDown()113 array_refcount_test::TearDown()
114 {
115    delete body;
116    body = NULL;
117 
118    ralloc_free(mem_ctx);
119    mem_ctx = NULL;
120 }
121 
122 static operand
deref_array(operand array,operand index)123 deref_array(operand array, operand index)
124 {
125    void *mem_ctx = ralloc_parent(array.val);
126 
127    ir_rvalue *val = new(mem_ctx) ir_dereference_array(array.val, index.val);
128 
129    return operand(val);
130 }
131 
132 static operand
deref_struct(operand s,const char * field)133 deref_struct(operand s, const char *field)
134 {
135    void *mem_ctx = ralloc_parent(s.val);
136 
137    ir_rvalue *val = new(mem_ctx) ir_dereference_record(s.val, field);
138 
139    return operand(val);
140 }
141 
142 /**
143  * Verify that only the specified set of ir_variables exists in the hash table
144  */
145 static void
validate_variables_in_hash_table(struct hash_table * ht,unsigned count,...)146 validate_variables_in_hash_table(struct hash_table *ht,
147                                  unsigned count,
148                                  ...)
149 {
150    ir_variable **vars = new ir_variable *[count];
151    va_list args;
152 
153    /* Make a copy of the list of expected ir_variables.  The copied list can
154     * be modified during the checking.
155     */
156    va_start(args, count);
157 
158    for (unsigned i = 0; i < count; i++)
159       vars[i] = va_arg(args, ir_variable *);
160 
161    va_end(args);
162 
163    struct hash_entry *entry;
164    hash_table_foreach(ht, entry) {
165       const ir_instruction *const ir = (ir_instruction *) entry->key;
166       const ir_variable *const v = ir->as_variable();
167 
168       if (v == NULL) {
169          ADD_FAILURE() << "Invalid junk in hash table: ir_type = "
170                        << ir->ir_type << ", address = "
171                        << (void *) ir;
172          continue;
173       }
174 
175       unsigned i;
176       for (i = 0; i < count; i++) {
177          if (vars[i] == NULL)
178             continue;
179 
180          if (vars[i] == v)
181             break;
182       }
183 
184       if (i == count) {
185             ADD_FAILURE() << "Invalid variable in hash table: \""
186                           << v->name << "\"";
187       } else {
188          /* As each variable is encountered, remove it from the set.  Don't
189           * bother compacting the set because we don't care about
190           * performance here.
191           */
192          vars[i] = NULL;
193       }
194    }
195 
196    /* Check that there's nothing left in the set. */
197    for (unsigned i = 0; i < count; i++) {
198       if (vars[i] != NULL) {
199          ADD_FAILURE() << "Variable was not in the hash table: \""
200                           << vars[i]->name << "\"";
201       }
202    }
203 
204    delete [] vars;
205 }
206 
TEST_F(array_refcount_test,ir_array_refcount_entry_initial_state_for_scalar)207 TEST_F(array_refcount_test, ir_array_refcount_entry_initial_state_for_scalar)
208 {
209    ir_variable *const var =
210       new(mem_ctx) ir_variable(glsl_type::int_type, "a", ir_var_auto);
211 
212    ir_array_refcount_entry entry(var);
213 
214    ASSERT_NE((void *)0, get_bits(entry));
215    EXPECT_FALSE(entry.is_referenced);
216    EXPECT_EQ(1, get_num_bits(entry));
217    EXPECT_EQ(0, get_array_depth(entry));
218    EXPECT_FALSE(entry.is_linearized_index_referenced(0));
219 }
220 
TEST_F(array_refcount_test,ir_array_refcount_entry_initial_state_for_vector)221 TEST_F(array_refcount_test, ir_array_refcount_entry_initial_state_for_vector)
222 {
223    ir_variable *const var =
224       new(mem_ctx) ir_variable(glsl_type::vec4_type, "a", ir_var_auto);
225 
226    ir_array_refcount_entry entry(var);
227 
228    ASSERT_NE((void *)0, get_bits(entry));
229    EXPECT_FALSE(entry.is_referenced);
230    EXPECT_EQ(1, get_num_bits(entry));
231    EXPECT_EQ(0, get_array_depth(entry));
232    EXPECT_FALSE(entry.is_linearized_index_referenced(0));
233 }
234 
TEST_F(array_refcount_test,ir_array_refcount_entry_initial_state_for_matrix)235 TEST_F(array_refcount_test, ir_array_refcount_entry_initial_state_for_matrix)
236 {
237    ir_variable *const var =
238       new(mem_ctx) ir_variable(glsl_type::mat4_type, "a", ir_var_auto);
239 
240    ir_array_refcount_entry entry(var);
241 
242    ASSERT_NE((void *)0, get_bits(entry));
243    EXPECT_FALSE(entry.is_referenced);
244    EXPECT_EQ(1, get_num_bits(entry));
245    EXPECT_EQ(0, get_array_depth(entry));
246    EXPECT_FALSE(entry.is_linearized_index_referenced(0));
247 }
248 
TEST_F(array_refcount_test,ir_array_refcount_entry_initial_state_for_array)249 TEST_F(array_refcount_test, ir_array_refcount_entry_initial_state_for_array)
250 {
251    ir_variable *const var =
252       new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
253                                "a",
254                                ir_var_auto);
255    const unsigned total_elements = var->type->arrays_of_arrays_size();
256 
257    ir_array_refcount_entry entry(var);
258 
259    ASSERT_NE((void *)0, get_bits(entry));
260    EXPECT_FALSE(entry.is_referenced);
261    EXPECT_EQ(total_elements, get_num_bits(entry));
262    EXPECT_EQ(3, get_array_depth(entry));
263 
264    for (unsigned i = 0; i < total_elements; i++)
265       EXPECT_FALSE(entry.is_linearized_index_referenced(i)) << "index = " << i;
266 }
267 
TEST_F(array_refcount_test,mark_array_elements_referenced_simple)268 TEST_F(array_refcount_test, mark_array_elements_referenced_simple)
269 {
270    ir_variable *const var =
271       new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
272                                "a",
273                                ir_var_auto);
274    const unsigned total_elements = var->type->arrays_of_arrays_size();
275 
276    ir_array_refcount_entry entry(var);
277 
278    static const array_deref_range dr[] = {
279       { 0, 5 }, { 1, 4 }, { 2, 3 }
280    };
281    const unsigned accessed_element = 0 + (1 * 5) + (2 * 4 * 5);
282 
283    entry.mark_array_elements_referenced(dr, 3);
284 
285    for (unsigned i = 0; i < total_elements; i++)
286       EXPECT_EQ(i == accessed_element, entry.is_linearized_index_referenced(i));
287 }
288 
TEST_F(array_refcount_test,mark_array_elements_referenced_whole_first_array)289 TEST_F(array_refcount_test, mark_array_elements_referenced_whole_first_array)
290 {
291    ir_variable *const var =
292       new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
293                                "a",
294                                ir_var_auto);
295 
296    ir_array_refcount_entry entry(var);
297 
298    static const array_deref_range dr[] = {
299       { 0, 5 }, { 1, 4 }, { 3, 3 }
300    };
301 
302    entry.mark_array_elements_referenced(dr, 3);
303 
304    for (unsigned i = 0; i < 3; i++) {
305       for (unsigned j = 0; j < 4; j++) {
306          for (unsigned k = 0; k < 5; k++) {
307             const bool accessed = (j == 1) && (k == 0);
308             const unsigned linearized_index = k + (j * 5) + (i * 4 * 5);
309 
310             EXPECT_EQ(accessed,
311                       entry.is_linearized_index_referenced(linearized_index));
312          }
313       }
314    }
315 }
316 
TEST_F(array_refcount_test,mark_array_elements_referenced_whole_second_array)317 TEST_F(array_refcount_test, mark_array_elements_referenced_whole_second_array)
318 {
319    ir_variable *const var =
320       new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
321                                "a",
322                                ir_var_auto);
323 
324    ir_array_refcount_entry entry(var);
325 
326    static const array_deref_range dr[] = {
327       { 0, 5 }, { 4, 4 }, { 1, 3 }
328    };
329 
330    entry.mark_array_elements_referenced(dr, 3);
331 
332    for (unsigned i = 0; i < 3; i++) {
333       for (unsigned j = 0; j < 4; j++) {
334          for (unsigned k = 0; k < 5; k++) {
335             const bool accessed = (i == 1) && (k == 0);
336             const unsigned linearized_index = k + (j * 5) + (i * 4 * 5);
337 
338             EXPECT_EQ(accessed,
339                       entry.is_linearized_index_referenced(linearized_index));
340          }
341       }
342    }
343 }
344 
TEST_F(array_refcount_test,mark_array_elements_referenced_whole_third_array)345 TEST_F(array_refcount_test, mark_array_elements_referenced_whole_third_array)
346 {
347    ir_variable *const var =
348       new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
349                                "a",
350                                ir_var_auto);
351 
352    ir_array_refcount_entry entry(var);
353 
354    static const array_deref_range dr[] = {
355       { 5, 5 }, { 2, 4 }, { 1, 3 }
356    };
357 
358    entry.mark_array_elements_referenced(dr, 3);
359 
360    for (unsigned i = 0; i < 3; i++) {
361       for (unsigned j = 0; j < 4; j++) {
362          for (unsigned k = 0; k < 5; k++) {
363             const bool accessed = (i == 1) && (j == 2);
364             const unsigned linearized_index = k + (j * 5) + (i * 4 * 5);
365 
366             EXPECT_EQ(accessed,
367                       entry.is_linearized_index_referenced(linearized_index));
368          }
369       }
370    }
371 }
372 
TEST_F(array_refcount_test,mark_array_elements_referenced_whole_first_and_third_arrays)373 TEST_F(array_refcount_test, mark_array_elements_referenced_whole_first_and_third_arrays)
374 {
375    ir_variable *const var =
376       new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
377                                "a",
378                                ir_var_auto);
379 
380    ir_array_refcount_entry entry(var);
381 
382    static const array_deref_range dr[] = {
383       { 5, 5 }, { 3, 4 }, { 3, 3 }
384    };
385 
386    entry.mark_array_elements_referenced(dr, 3);
387 
388    for (unsigned i = 0; i < 3; i++) {
389       for (unsigned j = 0; j < 4; j++) {
390          for (unsigned k = 0; k < 5; k++) {
391             const bool accessed = (j == 3);
392             const unsigned linearized_index = k + (j * 5) + (i * 4 * 5);
393 
394             EXPECT_EQ(accessed,
395                       entry.is_linearized_index_referenced(linearized_index));
396          }
397       }
398    }
399 }
400 
TEST_F(array_refcount_test,do_not_process_vector_indexing)401 TEST_F(array_refcount_test, do_not_process_vector_indexing)
402 {
403    /* Vectors and matrices can also be indexed in much the same manner as
404     * arrays.  The visitor should not try to track per-element accesses to
405     * these types.
406     */
407    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::float_type,
408                                                  "a",
409                                                  ir_var_auto);
410    ir_variable *var_b = new(mem_ctx) ir_variable(glsl_type::int_type,
411                                                  "b",
412                                                  ir_var_auto);
413    ir_variable *var_c = new(mem_ctx) ir_variable(glsl_type::vec4_type,
414                                                  "c",
415                                                  ir_var_auto);
416 
417    body->emit(assign(var_a, deref_array(var_c, var_b)));
418 
419    ir_array_refcount_visitor v;
420 
421    visit_list_elements(&v, &instructions);
422 
423    ir_array_refcount_entry *entry_a = v.get_variable_entry(var_a);
424    ir_array_refcount_entry *entry_b = v.get_variable_entry(var_b);
425    ir_array_refcount_entry *entry_c = v.get_variable_entry(var_c);
426 
427    EXPECT_TRUE(entry_a->is_referenced);
428    EXPECT_TRUE(entry_b->is_referenced);
429    EXPECT_TRUE(entry_c->is_referenced);
430 
431    /* As validated by previous tests, for non-array types, num_bits is 1. */
432    ASSERT_EQ(1, get_num_bits(*entry_c));
433    EXPECT_FALSE(entry_c->is_linearized_index_referenced(0));
434 }
435 
TEST_F(array_refcount_test,do_not_process_matrix_indexing)436 TEST_F(array_refcount_test, do_not_process_matrix_indexing)
437 {
438    /* Vectors and matrices can also be indexed in much the same manner as
439     * arrays.  The visitor should not try to track per-element accesses to
440     * these types.
441     */
442    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::vec4_type,
443                                                  "a",
444                                                  ir_var_auto);
445    ir_variable *var_b = new(mem_ctx) ir_variable(glsl_type::int_type,
446                                                  "b",
447                                                  ir_var_auto);
448    ir_variable *var_c = new(mem_ctx) ir_variable(glsl_type::mat4_type,
449                                                  "c",
450                                                  ir_var_auto);
451 
452    body->emit(assign(var_a, deref_array(var_c, var_b)));
453 
454    ir_array_refcount_visitor v;
455 
456    visit_list_elements(&v, &instructions);
457 
458    ir_array_refcount_entry *entry_a = v.get_variable_entry(var_a);
459    ir_array_refcount_entry *entry_b = v.get_variable_entry(var_b);
460    ir_array_refcount_entry *entry_c = v.get_variable_entry(var_c);
461 
462    EXPECT_TRUE(entry_a->is_referenced);
463    EXPECT_TRUE(entry_b->is_referenced);
464    EXPECT_TRUE(entry_c->is_referenced);
465 
466    /* As validated by previous tests, for non-array types, num_bits is 1. */
467    ASSERT_EQ(1, get_num_bits(*entry_c));
468    EXPECT_FALSE(entry_c->is_linearized_index_referenced(0));
469 }
470 
TEST_F(array_refcount_test,do_not_process_array_inside_structure)471 TEST_F(array_refcount_test, do_not_process_array_inside_structure)
472 {
473    /* Structures can contain arrays.  The visitor should not try to track
474     * per-element accesses to arrays contained inside structures.
475     */
476    const glsl_struct_field fields[] = {
477       glsl_struct_field(array_3_of_int, "i"),
478    };
479 
480    const glsl_type *const record_of_array_3_of_int =
481       glsl_type::get_record_instance(fields, ARRAY_SIZE(fields), "S");
482 
483    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::int_type,
484                                                  "a",
485                                                  ir_var_auto);
486 
487    ir_variable *var_b = new(mem_ctx) ir_variable(record_of_array_3_of_int,
488                                                  "b",
489                                                  ir_var_auto);
490 
491    /* a = b.i[2] */
492    body->emit(assign(var_a,
493                      deref_array(
494                         deref_struct(var_b, "i"),
495                         body->constant(int(2)))));
496 
497    ir_array_refcount_visitor v;
498 
499    visit_list_elements(&v, &instructions);
500 
501    ir_array_refcount_entry *entry_a = v.get_variable_entry(var_a);
502    ir_array_refcount_entry *entry_b = v.get_variable_entry(var_b);
503 
504    EXPECT_TRUE(entry_a->is_referenced);
505    EXPECT_TRUE(entry_b->is_referenced);
506 
507    ASSERT_EQ(1, get_num_bits(*entry_b));
508    EXPECT_FALSE(entry_b->is_linearized_index_referenced(0));
509 
510    validate_variables_in_hash_table(v.ht, 2, var_a, var_b);
511 }
512 
TEST_F(array_refcount_test,visit_simple_indexing)513 TEST_F(array_refcount_test, visit_simple_indexing)
514 {
515    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::vec4_type,
516                                                  "a",
517                                                  ir_var_auto);
518    ir_variable *var_b = new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
519                                                  "b",
520                                                  ir_var_auto);
521 
522    /* a = b[2][1][0] */
523    body->emit(assign(var_a,
524                      deref_array(
525                         deref_array(
526                            deref_array(var_b, body->constant(int(2))),
527                            body->constant(int(1))),
528                         body->constant(int(0)))));
529 
530    ir_array_refcount_visitor v;
531 
532    visit_list_elements(&v, &instructions);
533 
534    const unsigned accessed_element = 0 + (1 * 5) + (2 * 4 * 5);
535    ir_array_refcount_entry *entry_b = v.get_variable_entry(var_b);
536    const unsigned total_elements = var_b->type->arrays_of_arrays_size();
537 
538    for (unsigned i = 0; i < total_elements; i++)
539       EXPECT_EQ(i == accessed_element, entry_b->is_linearized_index_referenced(i)) <<
540          "i = " << i;
541 
542    validate_variables_in_hash_table(v.ht, 2, var_a, var_b);
543 }
544 
TEST_F(array_refcount_test,visit_whole_second_array_indexing)545 TEST_F(array_refcount_test, visit_whole_second_array_indexing)
546 {
547    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::vec4_type,
548                                                  "a",
549                                                  ir_var_auto);
550    ir_variable *var_b = new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
551                                                  "b",
552                                                  ir_var_auto);
553    ir_variable *var_i = new(mem_ctx) ir_variable(glsl_type::int_type,
554                                                  "i",
555                                                  ir_var_auto);
556 
557    /* a = b[2][i][1] */
558    body->emit(assign(var_a,
559                      deref_array(
560                         deref_array(
561                            deref_array(var_b, body->constant(int(2))),
562                            var_i),
563                         body->constant(int(1)))));
564 
565    ir_array_refcount_visitor v;
566 
567    visit_list_elements(&v, &instructions);
568 
569    ir_array_refcount_entry *const entry_b = v.get_variable_entry(var_b);
570    for (unsigned i = 0; i < 3; i++) {
571       for (unsigned j = 0; j < 4; j++) {
572          for (unsigned k = 0; k < 5; k++) {
573             const bool accessed = (i == 2) && (k == 1);
574             const unsigned linearized_index = k + (j * 5) + (i * 4 * 5);
575 
576             EXPECT_EQ(accessed,
577                       entry_b->is_linearized_index_referenced(linearized_index)) <<
578                "i = " << i;
579          }
580       }
581    }
582 
583    validate_variables_in_hash_table(v.ht, 3, var_a, var_b, var_i);
584 }
585 
TEST_F(array_refcount_test,visit_array_indexing_an_array)586 TEST_F(array_refcount_test, visit_array_indexing_an_array)
587 {
588    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::vec4_type,
589                                                  "a",
590                                                  ir_var_auto);
591    ir_variable *var_b = new(mem_ctx) ir_variable(array_3_of_array_4_of_array_5_of_vec4,
592                                                  "b",
593                                                  ir_var_auto);
594    ir_variable *var_c = new(mem_ctx) ir_variable(array_3_of_int,
595                                                  "c",
596                                                  ir_var_auto);
597    ir_variable *var_i = new(mem_ctx) ir_variable(glsl_type::int_type,
598                                                  "i",
599                                                  ir_var_auto);
600 
601    /* a = b[2][3][c[i]] */
602    body->emit(assign(var_a,
603                      deref_array(
604                         deref_array(
605                            deref_array(var_b, body->constant(int(2))),
606                            body->constant(int(3))),
607                         deref_array(var_c, var_i))));
608 
609    ir_array_refcount_visitor v;
610 
611    visit_list_elements(&v, &instructions);
612 
613    ir_array_refcount_entry *const entry_b = v.get_variable_entry(var_b);
614 
615    for (unsigned i = 0; i < 3; i++) {
616       for (unsigned j = 0; j < 4; j++) {
617          for (unsigned k = 0; k < 5; k++) {
618             const bool accessed = (i == 2) && (j == 3);
619             const unsigned linearized_index = k + (j * 5) + (i * 4 * 5);
620 
621             EXPECT_EQ(accessed,
622                       entry_b->is_linearized_index_referenced(linearized_index)) <<
623                "array b[" << i << "][" << j << "][" << k << "], " <<
624                "linear index = " << linearized_index;
625          }
626       }
627    }
628 
629    ir_array_refcount_entry *const entry_c = v.get_variable_entry(var_c);
630 
631    for (unsigned i = 0; i < var_c->type->array_size(); i++) {
632       EXPECT_EQ(true, entry_c->is_linearized_index_referenced(i)) <<
633          "array c, i = " << i;
634    }
635 
636    validate_variables_in_hash_table(v.ht, 4, var_a, var_b, var_c, var_i);
637 }
638 
TEST_F(array_refcount_test,visit_array_indexing_with_itself)639 TEST_F(array_refcount_test, visit_array_indexing_with_itself)
640 {
641    const glsl_type *const array_2_of_array_3_of_int =
642       glsl_type::get_array_instance(array_3_of_int, 2);
643 
644    const glsl_type *const array_2_of_array_2_of_array_3_of_int =
645       glsl_type::get_array_instance(array_2_of_array_3_of_int, 2);
646 
647    ir_variable *var_a = new(mem_ctx) ir_variable(glsl_type::int_type,
648                                                  "a",
649                                                  ir_var_auto);
650    ir_variable *var_b = new(mem_ctx) ir_variable(array_2_of_array_2_of_array_3_of_int,
651                                                  "b",
652                                                  ir_var_auto);
653 
654    /* Given GLSL code:
655     *
656     *    int b[2][2][3];
657     *    a = b[ b[0][0][0] ][ b[ b[0][1][0] ][ b[1][0][0] ][1] ][2]
658     *
659     * b[0][0][0], b[0][1][0], and b[1][0][0] are trivially accessed.
660     *
661     * b[*][*][1] and b[*][*][2] are accessed.
662     *
663     * Only b[1][1][0] is not accessed.
664     */
665    operand b000 = deref_array(
666       deref_array(
667          deref_array(var_b, body->constant(int(0))),
668          body->constant(int(0))),
669       body->constant(int(0)));
670 
671    operand b010 = deref_array(
672       deref_array(
673          deref_array(var_b, body->constant(int(0))),
674          body->constant(int(1))),
675       body->constant(int(0)));
676 
677    operand b100 = deref_array(
678       deref_array(
679          deref_array(var_b, body->constant(int(1))),
680          body->constant(int(0))),
681       body->constant(int(0)));
682 
683    operand b_b010_b100_1 = deref_array(
684       deref_array(
685          deref_array(var_b, b010),
686          b100),
687       body->constant(int(1)));
688 
689    body->emit(assign(var_a,
690                      deref_array(
691                         deref_array(
692                            deref_array(var_b, b000),
693                            b_b010_b100_1),
694                         body->constant(int(2)))));
695 
696    ir_array_refcount_visitor v;
697 
698    visit_list_elements(&v, &instructions);
699 
700    ir_array_refcount_entry *const entry_b = v.get_variable_entry(var_b);
701 
702    for (unsigned i = 0; i < 2; i++) {
703       for (unsigned j = 0; j < 2; j++) {
704          for (unsigned k = 0; k < 3; k++) {
705             const bool accessed = !(i == 1 && j == 1 && k == 0);
706             const unsigned linearized_index = k + (j * 3) + (i * 2 * 3);
707 
708             EXPECT_EQ(accessed,
709                       entry_b->is_linearized_index_referenced(linearized_index)) <<
710                "array b[" << i << "][" << j << "][" << k << "], " <<
711                "linear index = " << linearized_index;
712          }
713       }
714    }
715 
716    validate_variables_in_hash_table(v.ht, 2, var_a, var_b);
717 }
718