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_opt_algebraic.c
27 * This is the optimization pass for miscellaneous changes to instructions
28 * where we can simplify the operation by some knowledge about the specific
31 * Mostly this will be a matter of turning things into MOVs so that they can
32 * later be copy-propagated out.
36 #include "util/hash_table.h"
37 #include "util/u_math.h"
39 static inline uint32_t
40 index_hash(const void *key
)
42 return (uintptr_t)key
;
46 index_compare(const void *a
, const void *b
)
52 add_uniform(struct hash_table
*ht
, struct qreg reg
)
54 struct hash_entry
*entry
;
55 void *key
= (void *)(uintptr_t)reg
.index
;
57 entry
= _mesa_hash_table_search(ht
, key
);
61 _mesa_hash_table_insert(ht
, key
, (void *)(uintptr_t)1);
66 remove_uniform(struct hash_table
*ht
, struct qreg reg
)
68 struct hash_entry
*entry
;
69 void *key
= (void *)(uintptr_t)reg
.index
;
71 entry
= _mesa_hash_table_search(ht
, key
);
74 if (entry
->data
== NULL
)
75 _mesa_hash_table_remove(ht
, entry
);
79 is_lowerable_uniform(struct qinst
*inst
, int i
)
81 if (inst
->src
[i
].file
!= QFILE_UNIF
)
89 qir_lower_uniforms(struct vc4_compile
*c
)
91 struct simple_node
*node
;
92 struct hash_table
*ht
=
93 _mesa_hash_table_create(c
, index_hash
, index_compare
);
95 /* Walk the instruction list, finding which instructions have more
96 * than one uniform referenced, and add those uniform values to the
99 foreach(node
, &c
->instructions
) {
100 struct qinst
*inst
= (struct qinst
*)node
;
101 uint32_t nsrc
= qir_get_op_nsrc(inst
->op
);
104 for (int i
= 0; i
< nsrc
; i
++) {
105 if (inst
->src
[i
].file
== QFILE_UNIF
)
112 for (int i
= 0; i
< nsrc
; i
++) {
113 if (is_lowerable_uniform(inst
, i
))
114 add_uniform(ht
, inst
->src
[i
]);
118 while (ht
->entries
) {
119 /* Find the most commonly used uniform in instructions that
120 * need a uniform lowered.
122 uint32_t max_count
= 0;
123 uint32_t max_index
= 0;
124 struct hash_entry
*entry
;
125 hash_table_foreach(ht
, entry
) {
126 uint32_t count
= (uintptr_t)entry
->data
;
127 uint32_t index
= (uintptr_t)entry
->key
;
128 if (count
> max_count
) {
134 /* Now, find the instructions using this uniform and make them
135 * reference a temp instead.
137 struct qreg temp
= qir_get_temp(c
);
138 struct qreg unif
= { QFILE_UNIF
, max_index
};
139 struct qinst
*mov
= qir_inst(QOP_MOV
, temp
, unif
, c
->undef
);
140 insert_at_head(&c
->instructions
, &mov
->link
);
141 c
->defs
[temp
.index
] = mov
;
142 foreach(node
, &c
->instructions
) {
143 struct qinst
*inst
= (struct qinst
*)node
;
144 uint32_t nsrc
= qir_get_op_nsrc(inst
->op
);
147 for (int i
= 0; i
< nsrc
; i
++) {
148 if (inst
->src
[i
].file
== QFILE_UNIF
)
155 for (int i
= 0; i
< nsrc
; i
++) {
156 if (is_lowerable_uniform(inst
, i
) &&
157 inst
->src
[i
].index
== max_index
) {
159 remove_uniform(ht
, unif
);
164 /* If the instruction doesn't need lowering any more,
165 * then drop it from the list.
168 for (int i
= 0; i
< nsrc
; i
++) {
169 if (is_lowerable_uniform(inst
, i
))
170 remove_uniform(ht
, inst
->src
[i
]);
176 _mesa_hash_table_destroy(ht
, NULL
);