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
29using namespace ir_builder;
30
31class array_refcount_test : public ::testing::Test {
32public:
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    */
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    */
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    */
87   unsigned get_array_depth(const ir_array_refcount_entry &entry)
88   {
89      return entry.array_depth;
90   }
91};
92
93void
94array_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
114void
115array_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
126static operand
127deref_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
136static operand
137deref_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 */
149static void
150validate_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
210TEST_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
224TEST_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
238TEST_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
252TEST_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
271TEST_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
293TEST_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
322TEST_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
351TEST_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
380TEST_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
409TEST_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
444TEST_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
479TEST_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
521TEST_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
553TEST_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
594TEST_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
647TEST_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