2 * Copyright © 2014 Broadcom
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 DEALINGS
25 * @file vc4_qir_lower_uniforms.c
27 * This is the pre-code-generation pass for fixing up instructions that try to
28 * read from multiple uniform values.
32 #include "util/hash_table.h"
33 #include "util/u_math.h"
35 static inline uint32_t
36 index_hash(const void *key
)
38 return (uintptr_t)key
;
42 index_compare(const void *a
, const void *b
)
48 add_uniform(struct hash_table
*ht
, struct qreg reg
)
50 struct hash_entry
*entry
;
51 void *key
= (void *)(uintptr_t)(reg
.index
+ 1);
53 entry
= _mesa_hash_table_search(ht
, key
);
57 _mesa_hash_table_insert(ht
, key
, (void *)(uintptr_t)1);
62 remove_uniform(struct hash_table
*ht
, struct qreg reg
)
64 struct hash_entry
*entry
;
65 void *key
= (void *)(uintptr_t)(reg
.index
+ 1);
67 entry
= _mesa_hash_table_search(ht
, key
);
69 entry
->data
= (void *)(((uintptr_t) entry
->data
) - 1);
70 if (entry
->data
== NULL
)
71 _mesa_hash_table_remove(ht
, entry
);
75 is_lowerable_uniform(struct qinst
*inst
, int i
)
77 if (inst
->src
[i
].file
!= QFILE_UNIF
)
80 return i
!= qir_get_tex_uniform_src(inst
);
84 /* Returns the number of different uniform values referenced by the
88 qir_get_instruction_uniform_count(struct qinst
*inst
)
92 for (int i
= 0; i
< qir_get_nsrc(inst
); i
++) {
93 if (inst
->src
[i
].file
!= QFILE_UNIF
)
96 bool is_duplicate
= false;
97 for (int j
= 0; j
< i
; j
++) {
98 if (inst
->src
[j
].file
== QFILE_UNIF
&&
99 inst
->src
[j
].index
== inst
->src
[i
].index
) {
112 qir_lower_uniforms(struct vc4_compile
*c
)
114 struct hash_table
*ht
=
115 _mesa_hash_table_create(c
, index_hash
, index_compare
);
117 /* Walk the instruction list, finding which instructions have more
118 * than one uniform referenced, and add those uniform values to the
121 qir_for_each_inst_inorder(inst
, c
) {
122 uint32_t nsrc
= qir_get_nsrc(inst
);
124 if (qir_get_instruction_uniform_count(inst
) <= 1)
127 for (int i
= 0; i
< nsrc
; i
++) {
128 if (is_lowerable_uniform(inst
, i
))
129 add_uniform(ht
, inst
->src
[i
]);
133 while (ht
->entries
) {
134 /* Find the most commonly used uniform in instructions that
135 * need a uniform lowered.
137 uint32_t max_count
= 0;
138 uint32_t max_index
= 0;
139 hash_table_foreach(ht
, entry
) {
140 uint32_t count
= (uintptr_t)entry
->data
;
141 uint32_t index
= (uintptr_t)entry
->key
- 1;
142 if (count
> max_count
) {
148 struct qreg unif
= qir_reg(QFILE_UNIF
, max_index
);
150 /* Now, find the instructions using this uniform and make them
151 * reference a temp instead.
153 qir_for_each_block(block
, c
) {
154 struct qinst
*mov
= NULL
;
156 qir_for_each_inst(inst
, block
) {
157 uint32_t nsrc
= qir_get_nsrc(inst
);
159 uint32_t count
= qir_get_instruction_uniform_count(inst
);
164 /* If the block doesn't have a load of hte
165 * uniform yet, add it. We could potentially
166 * do better and CSE MOVs from multiple blocks
167 * into dominating blocks, except that may
168 * cause troubles for register allocation.
171 mov
= qir_inst(QOP_MOV
, qir_get_temp(c
),
174 &block
->instructions
);
175 c
->defs
[mov
->dst
.index
] = mov
;
178 bool removed
= false;
179 for (int i
= 0; i
< nsrc
; i
++) {
180 if (is_lowerable_uniform(inst
, i
) &&
181 inst
->src
[i
].index
== max_index
) {
182 inst
->src
[i
] = mov
->dst
;
183 remove_uniform(ht
, unif
);
190 /* If the instruction doesn't need lowering any more,
191 * then drop it from the list.
194 for (int i
= 0; i
< nsrc
; i
++) {
195 if (is_lowerable_uniform(inst
, i
))
196 remove_uniform(ht
, inst
->src
[i
]);
203 _mesa_hash_table_destroy(ht
, NULL
);