2 * Copyright © 2016 Intel Corporation
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:
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
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.
23 #include <gtest/gtest.h>
25 #include "ir_array_refcount.h"
26 #include "ir_builder.h"
27 #include "util/hash_table.h"
29 using namespace ir_builder
;
31 class array_refcount_test
: public ::testing::Test
{
34 virtual void TearDown();
36 exec_list instructions
;
41 * glsl_type for a vec4[3][4][5].
43 * The exceptionally verbose name is picked because it matches the syntax
44 * of http://cdecl.org/.
46 const glsl_type
*array_3_of_array_4_of_array_5_of_vec4
;
49 * glsl_type for a int[3].
51 * The exceptionally verbose name is picked because it matches the syntax
52 * of http://cdecl.org/.
54 const glsl_type
*array_3_of_int
;
57 * Wrapper to access private member "bits" of ir_array_refcount_entry
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.
63 const BITSET_WORD
*get_bits(const ir_array_refcount_entry
&entry
)
69 * Wrapper to access private member "num_bits" of ir_array_refcount_entry
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.
75 unsigned get_num_bits(const ir_array_refcount_entry
&entry
)
77 return entry
.num_bits
;
81 * Wrapper to access private member "array_depth" of ir_array_refcount_entry
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.
87 unsigned get_array_depth(const ir_array_refcount_entry
&entry
)
89 return entry
.array_depth
;
94 array_refcount_test::SetUp()
96 mem_ctx
= ralloc_context(NULL
);
98 instructions
.make_empty();
99 body
= new ir_factory(&instructions
, mem_ctx
);
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);
109 array_3_of_int
= glsl_type::get_array_instance(glsl_type::int_type
, 3);
113 array_refcount_test::TearDown()
118 ralloc_free(mem_ctx
);
123 deref_array(operand array
, operand index
)
125 void *mem_ctx
= ralloc_parent(array
.val
);
127 ir_rvalue
*val
= new(mem_ctx
) ir_dereference_array(array
.val
, index
.val
);
133 deref_struct(operand s
, const char *field
)
135 void *mem_ctx
= ralloc_parent(s
.val
);
137 ir_rvalue
*val
= new(mem_ctx
) ir_dereference_record(s
.val
, field
);
143 * Verify that only the specified set of ir_variables exists in the hash table
146 validate_variables_in_hash_table(struct hash_table
*ht
,
150 ir_variable
**vars
= new ir_variable
*[count
];
153 /* Make a copy of the list of expected ir_variables. The copied list can
154 * be modified during the checking.
156 va_start(args
, count
);
158 for (unsigned i
= 0; i
< count
; i
++)
159 vars
[i
] = va_arg(args
, ir_variable
*);
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();
169 ADD_FAILURE() << "Invalid junk in hash table: ir_type = "
170 << ir
->ir_type
<< ", address = "
176 for (i
= 0; i
< count
; i
++) {
185 ADD_FAILURE() << "Invalid variable in hash table: \""
188 /* As each variable is encountered, remove it from the set. Don't
189 * bother compacting the set because we don't care about
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
<< "\"";
207 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_scalar
)
209 ir_variable
*const var
=
210 new(mem_ctx
) ir_variable(glsl_type::int_type
, "a", ir_var_auto
);
212 ir_array_refcount_entry
entry(var
);
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));
221 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_vector
)
223 ir_variable
*const var
=
224 new(mem_ctx
) ir_variable(glsl_type::vec4_type
, "a", ir_var_auto
);
226 ir_array_refcount_entry
entry(var
);
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));
235 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_matrix
)
237 ir_variable
*const var
=
238 new(mem_ctx
) ir_variable(glsl_type::mat4_type
, "a", ir_var_auto
);
240 ir_array_refcount_entry
entry(var
);
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));
249 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_array
)
251 ir_variable
*const var
=
252 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
255 const unsigned total_elements
= var
->type
->arrays_of_arrays_size();
257 ir_array_refcount_entry
entry(var
);
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
));
264 for (unsigned i
= 0; i
< total_elements
; i
++)
265 EXPECT_FALSE(entry
.is_linearized_index_referenced(i
)) << "index = " << i
;
268 TEST_F(array_refcount_test
, mark_array_elements_referenced_simple
)
270 ir_variable
*const var
=
271 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
274 const unsigned total_elements
= var
->type
->arrays_of_arrays_size();
276 ir_array_refcount_entry
entry(var
);
278 static const array_deref_range dr
[] = {
279 { 0, 5 }, { 1, 4 }, { 2, 3 }
281 const unsigned accessed_element
= 0 + (1 * 5) + (2 * 4 * 5);
283 entry
.mark_array_elements_referenced(dr
, 3);
285 for (unsigned i
= 0; i
< total_elements
; i
++)
286 EXPECT_EQ(i
== accessed_element
, entry
.is_linearized_index_referenced(i
));
289 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_first_array
)
291 ir_variable
*const var
=
292 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
296 ir_array_refcount_entry
entry(var
);
298 static const array_deref_range dr
[] = {
299 { 0, 5 }, { 1, 4 }, { 3, 3 }
302 entry
.mark_array_elements_referenced(dr
, 3);
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);
311 entry
.is_linearized_index_referenced(linearized_index
));
317 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_second_array
)
319 ir_variable
*const var
=
320 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
324 ir_array_refcount_entry
entry(var
);
326 static const array_deref_range dr
[] = {
327 { 0, 5 }, { 4, 4 }, { 1, 3 }
330 entry
.mark_array_elements_referenced(dr
, 3);
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);
339 entry
.is_linearized_index_referenced(linearized_index
));
345 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_third_array
)
347 ir_variable
*const var
=
348 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
352 ir_array_refcount_entry
entry(var
);
354 static const array_deref_range dr
[] = {
355 { 5, 5 }, { 2, 4 }, { 1, 3 }
358 entry
.mark_array_elements_referenced(dr
, 3);
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);
367 entry
.is_linearized_index_referenced(linearized_index
));
373 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_first_and_third_arrays
)
375 ir_variable
*const var
=
376 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
380 ir_array_refcount_entry
entry(var
);
382 static const array_deref_range dr
[] = {
383 { 5, 5 }, { 3, 4 }, { 3, 3 }
386 entry
.mark_array_elements_referenced(dr
, 3);
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);
395 entry
.is_linearized_index_referenced(linearized_index
));
401 TEST_F(array_refcount_test
, do_not_process_vector_indexing
)
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
407 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::float_type
,
410 ir_variable
*var_b
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
413 ir_variable
*var_c
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
417 body
->emit(assign(var_a
, deref_array(var_c
, var_b
)));
419 ir_array_refcount_visitor v
;
421 visit_list_elements(&v
, &instructions
);
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
);
427 EXPECT_TRUE(entry_a
->is_referenced
);
428 EXPECT_TRUE(entry_b
->is_referenced
);
429 EXPECT_TRUE(entry_c
->is_referenced
);
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));
436 TEST_F(array_refcount_test
, do_not_process_matrix_indexing
)
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
442 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
445 ir_variable
*var_b
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
448 ir_variable
*var_c
= new(mem_ctx
) ir_variable(glsl_type::mat4_type
,
452 body
->emit(assign(var_a
, deref_array(var_c
, var_b
)));
454 ir_array_refcount_visitor v
;
456 visit_list_elements(&v
, &instructions
);
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
);
462 EXPECT_TRUE(entry_a
->is_referenced
);
463 EXPECT_TRUE(entry_b
->is_referenced
);
464 EXPECT_TRUE(entry_c
->is_referenced
);
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));
471 TEST_F(array_refcount_test
, do_not_process_array_inside_structure
)
473 /* Structures can contain arrays. The visitor should not try to track
474 * per-element accesses to arrays contained inside structures.
476 const glsl_struct_field fields
[] = {
477 glsl_struct_field(array_3_of_int
, "i"),
480 const glsl_type
*const record_of_array_3_of_int
=
481 glsl_type::get_record_instance(fields
, ARRAY_SIZE(fields
), "S");
483 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
487 ir_variable
*var_b
= new(mem_ctx
) ir_variable(record_of_array_3_of_int
,
492 body
->emit(assign(var_a
,
494 deref_struct(var_b
, "i"),
495 body
->constant(int(2)))));
497 ir_array_refcount_visitor v
;
499 visit_list_elements(&v
, &instructions
);
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
);
504 EXPECT_TRUE(entry_a
->is_referenced
);
505 EXPECT_TRUE(entry_b
->is_referenced
);
507 ASSERT_EQ(1, get_num_bits(*entry_b
));
508 EXPECT_FALSE(entry_b
->is_linearized_index_referenced(0));
510 validate_variables_in_hash_table(v
.ht
, 2, var_a
, var_b
);
513 TEST_F(array_refcount_test
, visit_simple_indexing
)
515 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
518 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
523 body
->emit(assign(var_a
,
526 deref_array(var_b
, body
->constant(int(2))),
527 body
->constant(int(1))),
528 body
->constant(int(0)))));
530 ir_array_refcount_visitor v
;
532 visit_list_elements(&v
, &instructions
);
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();
538 for (unsigned i
= 0; i
< total_elements
; i
++)
539 EXPECT_EQ(i
== accessed_element
, entry_b
->is_linearized_index_referenced(i
)) <<
542 validate_variables_in_hash_table(v
.ht
, 2, var_a
, var_b
);
545 TEST_F(array_refcount_test
, visit_whole_second_array_indexing
)
547 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
550 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
553 ir_variable
*var_i
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
558 body
->emit(assign(var_a
,
561 deref_array(var_b
, body
->constant(int(2))),
563 body
->constant(int(1)))));
565 ir_array_refcount_visitor v
;
567 visit_list_elements(&v
, &instructions
);
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);
577 entry_b
->is_linearized_index_referenced(linearized_index
)) <<
583 validate_variables_in_hash_table(v
.ht
, 3, var_a
, var_b
, var_i
);
586 TEST_F(array_refcount_test
, visit_array_indexing_an_array
)
588 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
591 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
594 ir_variable
*var_c
= new(mem_ctx
) ir_variable(array_3_of_int
,
597 ir_variable
*var_i
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
601 /* a = b[2][3][c[i]] */
602 body
->emit(assign(var_a
,
605 deref_array(var_b
, body
->constant(int(2))),
606 body
->constant(int(3))),
607 deref_array(var_c
, var_i
))));
609 ir_array_refcount_visitor v
;
611 visit_list_elements(&v
, &instructions
);
613 ir_array_refcount_entry
*const entry_b
= v
.get_variable_entry(var_b
);
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);
622 entry_b
->is_linearized_index_referenced(linearized_index
)) <<
623 "array b[" << i
<< "][" << j
<< "][" << k
<< "], " <<
624 "linear index = " << linearized_index
;
629 ir_array_refcount_entry
*const entry_c
= v
.get_variable_entry(var_c
);
631 for (unsigned 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
;
636 validate_variables_in_hash_table(v
.ht
, 4, var_a
, var_b
, var_c
, var_i
);
639 TEST_F(array_refcount_test
, visit_array_indexing_with_itself
)
641 const glsl_type
*const array_2_of_array_3_of_int
=
642 glsl_type::get_array_instance(array_3_of_int
, 2);
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);
647 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
650 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_2_of_array_2_of_array_3_of_int
,
657 * a = b[ b[0][0][0] ][ b[ b[0][1][0] ][ b[1][0][0] ][1] ][2]
659 * b[0][0][0], b[0][1][0], and b[1][0][0] are trivially accessed.
661 * b[*][*][1] and b[*][*][2] are accessed.
663 * Only b[1][1][0] is not accessed.
665 operand b000
= deref_array(
667 deref_array(var_b
, body
->constant(int(0))),
668 body
->constant(int(0))),
669 body
->constant(int(0)));
671 operand b010
= deref_array(
673 deref_array(var_b
, body
->constant(int(0))),
674 body
->constant(int(1))),
675 body
->constant(int(0)));
677 operand b100
= deref_array(
679 deref_array(var_b
, body
->constant(int(1))),
680 body
->constant(int(0))),
681 body
->constant(int(0)));
683 operand b_b010_b100_1
= deref_array(
685 deref_array(var_b
, b010
),
687 body
->constant(int(1)));
689 body
->emit(assign(var_a
,
692 deref_array(var_b
, b000
),
694 body
->constant(int(2)))));
696 ir_array_refcount_visitor v
;
698 visit_list_elements(&v
, &instructions
);
700 ir_array_refcount_entry
*const entry_b
= v
.get_variable_entry(var_b
);
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);
709 entry_b
->is_linearized_index_referenced(linearized_index
)) <<
710 "array b[" << i
<< "][" << j
<< "][" << k
<< "], " <<
711 "linear index = " << linearized_index
;
716 validate_variables_in_hash_table(v
.ht
, 2, var_a
, var_b
);