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