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