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