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 (int 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