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 hash_table_foreach(ht
, entry
) {
164 const ir_instruction
*const ir
= (ir_instruction
*) entry
->key
;
165 const ir_variable
*const v
= ir
->as_variable();
168 ADD_FAILURE() << "Invalid junk in hash table: ir_type = "
169 << ir
->ir_type
<< ", address = "
175 for (i
= 0; i
< count
; i
++) {
184 ADD_FAILURE() << "Invalid variable in hash table: \""
187 /* As each variable is encountered, remove it from the set. Don't
188 * bother compacting the set because we don't care about
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
<< "\"";
206 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_scalar
)
208 ir_variable
*const var
=
209 new(mem_ctx
) ir_variable(glsl_type::int_type
, "a", ir_var_auto
);
211 ir_array_refcount_entry
entry(var
);
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));
220 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_vector
)
222 ir_variable
*const var
=
223 new(mem_ctx
) ir_variable(glsl_type::vec4_type
, "a", ir_var_auto
);
225 ir_array_refcount_entry
entry(var
);
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));
234 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_matrix
)
236 ir_variable
*const var
=
237 new(mem_ctx
) ir_variable(glsl_type::mat4_type
, "a", ir_var_auto
);
239 ir_array_refcount_entry
entry(var
);
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));
248 TEST_F(array_refcount_test
, ir_array_refcount_entry_initial_state_for_array
)
250 ir_variable
*const var
=
251 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
254 const unsigned total_elements
= var
->type
->arrays_of_arrays_size();
256 ir_array_refcount_entry
entry(var
);
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
));
263 for (unsigned i
= 0; i
< total_elements
; i
++)
264 EXPECT_FALSE(entry
.is_linearized_index_referenced(i
)) << "index = " << i
;
267 TEST_F(array_refcount_test
, mark_array_elements_referenced_simple
)
269 ir_variable
*const var
=
270 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
273 const unsigned total_elements
= var
->type
->arrays_of_arrays_size();
275 ir_array_refcount_entry
entry(var
);
277 static const array_deref_range dr
[] = {
278 { 0, 5 }, { 1, 4 }, { 2, 3 }
280 const unsigned accessed_element
= 0 + (1 * 5) + (2 * 4 * 5);
282 entry
.mark_array_elements_referenced(dr
, 3);
284 for (unsigned i
= 0; i
< total_elements
; i
++)
285 EXPECT_EQ(i
== accessed_element
, entry
.is_linearized_index_referenced(i
));
288 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_first_array
)
290 ir_variable
*const var
=
291 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
295 ir_array_refcount_entry
entry(var
);
297 static const array_deref_range dr
[] = {
298 { 0, 5 }, { 1, 4 }, { 3, 3 }
301 entry
.mark_array_elements_referenced(dr
, 3);
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);
310 entry
.is_linearized_index_referenced(linearized_index
));
316 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_second_array
)
318 ir_variable
*const var
=
319 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
323 ir_array_refcount_entry
entry(var
);
325 static const array_deref_range dr
[] = {
326 { 0, 5 }, { 4, 4 }, { 1, 3 }
329 entry
.mark_array_elements_referenced(dr
, 3);
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);
338 entry
.is_linearized_index_referenced(linearized_index
));
344 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_third_array
)
346 ir_variable
*const var
=
347 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
351 ir_array_refcount_entry
entry(var
);
353 static const array_deref_range dr
[] = {
354 { 5, 5 }, { 2, 4 }, { 1, 3 }
357 entry
.mark_array_elements_referenced(dr
, 3);
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);
366 entry
.is_linearized_index_referenced(linearized_index
));
372 TEST_F(array_refcount_test
, mark_array_elements_referenced_whole_first_and_third_arrays
)
374 ir_variable
*const var
=
375 new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
379 ir_array_refcount_entry
entry(var
);
381 static const array_deref_range dr
[] = {
382 { 5, 5 }, { 3, 4 }, { 3, 3 }
385 entry
.mark_array_elements_referenced(dr
, 3);
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);
394 entry
.is_linearized_index_referenced(linearized_index
));
400 TEST_F(array_refcount_test
, do_not_process_vector_indexing
)
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
406 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::float_type
,
409 ir_variable
*var_b
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
412 ir_variable
*var_c
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
416 body
->emit(assign(var_a
, deref_array(var_c
, var_b
)));
418 ir_array_refcount_visitor v
;
420 visit_list_elements(&v
, &instructions
);
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
);
426 EXPECT_TRUE(entry_a
->is_referenced
);
427 EXPECT_TRUE(entry_b
->is_referenced
);
428 EXPECT_TRUE(entry_c
->is_referenced
);
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));
435 TEST_F(array_refcount_test
, do_not_process_matrix_indexing
)
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
441 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
444 ir_variable
*var_b
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
447 ir_variable
*var_c
= new(mem_ctx
) ir_variable(glsl_type::mat4_type
,
451 body
->emit(assign(var_a
, deref_array(var_c
, var_b
)));
453 ir_array_refcount_visitor v
;
455 visit_list_elements(&v
, &instructions
);
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
);
461 EXPECT_TRUE(entry_a
->is_referenced
);
462 EXPECT_TRUE(entry_b
->is_referenced
);
463 EXPECT_TRUE(entry_c
->is_referenced
);
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));
470 TEST_F(array_refcount_test
, do_not_process_array_inside_structure
)
472 /* Structures can contain arrays. The visitor should not try to track
473 * per-element accesses to arrays contained inside structures.
475 const glsl_struct_field fields
[] = {
476 glsl_struct_field(array_3_of_int
, "i"),
479 const glsl_type
*const record_of_array_3_of_int
=
480 glsl_type::get_record_instance(fields
, ARRAY_SIZE(fields
), "S");
482 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
486 ir_variable
*var_b
= new(mem_ctx
) ir_variable(record_of_array_3_of_int
,
491 body
->emit(assign(var_a
,
493 deref_struct(var_b
, "i"),
494 body
->constant(int(2)))));
496 ir_array_refcount_visitor v
;
498 visit_list_elements(&v
, &instructions
);
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
);
503 EXPECT_TRUE(entry_a
->is_referenced
);
504 EXPECT_TRUE(entry_b
->is_referenced
);
506 ASSERT_EQ(1, get_num_bits(*entry_b
));
507 EXPECT_FALSE(entry_b
->is_linearized_index_referenced(0));
509 validate_variables_in_hash_table(v
.ht
, 2, var_a
, var_b
);
512 TEST_F(array_refcount_test
, visit_simple_indexing
)
514 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
517 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
522 body
->emit(assign(var_a
,
525 deref_array(var_b
, body
->constant(int(2))),
526 body
->constant(int(1))),
527 body
->constant(int(0)))));
529 ir_array_refcount_visitor v
;
531 visit_list_elements(&v
, &instructions
);
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();
537 for (unsigned i
= 0; i
< total_elements
; i
++)
538 EXPECT_EQ(i
== accessed_element
, entry_b
->is_linearized_index_referenced(i
)) <<
541 validate_variables_in_hash_table(v
.ht
, 2, var_a
, var_b
);
544 TEST_F(array_refcount_test
, visit_whole_second_array_indexing
)
546 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
549 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
552 ir_variable
*var_i
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
557 body
->emit(assign(var_a
,
560 deref_array(var_b
, body
->constant(int(2))),
562 body
->constant(int(1)))));
564 ir_array_refcount_visitor v
;
566 visit_list_elements(&v
, &instructions
);
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);
576 entry_b
->is_linearized_index_referenced(linearized_index
)) <<
582 validate_variables_in_hash_table(v
.ht
, 3, var_a
, var_b
, var_i
);
585 TEST_F(array_refcount_test
, visit_array_indexing_an_array
)
587 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::vec4_type
,
590 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_3_of_array_4_of_array_5_of_vec4
,
593 ir_variable
*var_c
= new(mem_ctx
) ir_variable(array_3_of_int
,
596 ir_variable
*var_i
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
600 /* a = b[2][3][c[i]] */
601 body
->emit(assign(var_a
,
604 deref_array(var_b
, body
->constant(int(2))),
605 body
->constant(int(3))),
606 deref_array(var_c
, var_i
))));
608 ir_array_refcount_visitor v
;
610 visit_list_elements(&v
, &instructions
);
612 ir_array_refcount_entry
*const entry_b
= v
.get_variable_entry(var_b
);
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);
621 entry_b
->is_linearized_index_referenced(linearized_index
)) <<
622 "array b[" << i
<< "][" << j
<< "][" << k
<< "], " <<
623 "linear index = " << linearized_index
;
628 ir_array_refcount_entry
*const entry_c
= v
.get_variable_entry(var_c
);
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
;
635 validate_variables_in_hash_table(v
.ht
, 4, var_a
, var_b
, var_c
, var_i
);
638 TEST_F(array_refcount_test
, visit_array_indexing_with_itself
)
640 const glsl_type
*const array_2_of_array_3_of_int
=
641 glsl_type::get_array_instance(array_3_of_int
, 2);
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);
646 ir_variable
*var_a
= new(mem_ctx
) ir_variable(glsl_type::int_type
,
649 ir_variable
*var_b
= new(mem_ctx
) ir_variable(array_2_of_array_2_of_array_3_of_int
,
656 * a = b[ b[0][0][0] ][ b[ b[0][1][0] ][ b[1][0][0] ][1] ][2]
658 * b[0][0][0], b[0][1][0], and b[1][0][0] are trivially accessed.
660 * b[*][*][1] and b[*][*][2] are accessed.
662 * Only b[1][1][0] is not accessed.
664 operand b000
= deref_array(
666 deref_array(var_b
, body
->constant(int(0))),
667 body
->constant(int(0))),
668 body
->constant(int(0)));
670 operand b010
= deref_array(
672 deref_array(var_b
, body
->constant(int(0))),
673 body
->constant(int(1))),
674 body
->constant(int(0)));
676 operand b100
= deref_array(
678 deref_array(var_b
, body
->constant(int(1))),
679 body
->constant(int(0))),
680 body
->constant(int(0)));
682 operand b_b010_b100_1
= deref_array(
684 deref_array(var_b
, b010
),
686 body
->constant(int(1)));
688 body
->emit(assign(var_a
,
691 deref_array(var_b
, b000
),
693 body
->constant(int(2)))));
695 ir_array_refcount_visitor v
;
697 visit_list_elements(&v
, &instructions
);
699 ir_array_refcount_entry
*const entry_b
= v
.get_variable_entry(var_b
);
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);
708 entry_b
->is_linearized_index_referenced(linearized_index
)) <<
709 "array b[" << i
<< "][" << j
<< "][" << k
<< "], " <<
710 "linear index = " << linearized_index
;
715 validate_variables_in_hash_table(v
.ht
, 2, var_a
, var_b
);