1 /*
2 * Copyright (c) 2017 Lima Project
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, sub license,
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
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the 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 NON-INFRINGEMENT. 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 */
24
25 #include "util/ralloc.h"
26
27 #include "ppir.h"
28
ppir_instr_create(ppir_block * block)29 ppir_instr *ppir_instr_create(ppir_block *block)
30 {
31 ppir_instr *instr = rzalloc(block, ppir_instr);
32 if (!instr)
33 return NULL;
34
35 list_inithead(&instr->succ_list);
36 list_inithead(&instr->pred_list);
37
38 instr->index = block->comp->cur_instr_index++;
39 instr->reg_pressure = -1;
40
41 list_addtail(&instr->list, &block->instr_list);
42 return instr;
43 }
44
ppir_instr_add_dep(ppir_instr * succ,ppir_instr * pred)45 void ppir_instr_add_dep(ppir_instr *succ, ppir_instr *pred)
46 {
47 /* don't add duplicated instr */
48 ppir_instr_foreach_pred(succ, dep) {
49 if (pred == dep->pred)
50 return;
51 }
52
53 ppir_dep *dep = ralloc(succ, ppir_dep);
54 dep->pred = pred;
55 dep->succ = succ;
56 list_addtail(&dep->pred_link, &succ->pred_list);
57 list_addtail(&dep->succ_link, &pred->succ_list);
58 }
59
ppir_instr_insert_mul_node(ppir_node * add,ppir_node * mul)60 void ppir_instr_insert_mul_node(ppir_node *add, ppir_node *mul)
61 {
62 ppir_instr *instr = add->instr;
63 int pos = mul->instr_pos;
64 int *slots = ppir_op_infos[mul->op].slots;
65
66 for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) {
67 /* possible to insert at required place */
68 if (slots[i] == pos) {
69 if (!instr->slots[pos]) {
70 ppir_alu_node *add_alu = ppir_node_to_alu(add);
71 ppir_alu_node *mul_alu = ppir_node_to_alu(mul);
72 ppir_dest *dest = &mul_alu->dest;
73 int pipeline = pos == PPIR_INSTR_SLOT_ALU_VEC_MUL ?
74 ppir_pipeline_reg_vmul : ppir_pipeline_reg_fmul;
75
76 /* ^vmul/^fmul can't be used as last arg */
77 if (add_alu->num_src > 1) {
78 ppir_src *last_src = add_alu->src + add_alu->num_src - 1;
79 if (ppir_node_target_equal(last_src, dest))
80 return;
81 }
82
83 /* update add node src to use pipeline reg */
84 ppir_src *src = add_alu->src;
85 if (add_alu->num_src == 3) {
86 if (ppir_node_target_equal(src, dest)) {
87 src->type = ppir_target_pipeline;
88 src->pipeline = pipeline;
89 }
90
91 if (ppir_node_target_equal(++src, dest)) {
92 src->type = ppir_target_pipeline;
93 src->pipeline = pipeline;
94 }
95 }
96 else {
97 assert(ppir_node_target_equal(src, dest));
98 src->type = ppir_target_pipeline;
99 src->pipeline = pipeline;
100 }
101
102 /* update mul node dest to output to pipeline reg */
103 dest->type = ppir_target_pipeline;
104 dest->pipeline = pipeline;
105
106 instr->slots[pos] = mul;
107 mul->instr = instr;
108 }
109 return;
110 }
111 }
112 }
113
114 /* check whether a const slot fix into another const slot */
ppir_instr_insert_const(ppir_const * dst,const ppir_const * src,uint8_t * swizzle)115 static bool ppir_instr_insert_const(ppir_const *dst, const ppir_const *src,
116 uint8_t *swizzle)
117 {
118 int i, j;
119
120 for (i = 0; i < src->num; i++) {
121 for (j = 0; j < dst->num; j++) {
122 if (src->value[i].ui == dst->value[j].ui)
123 break;
124 }
125
126 if (j == dst->num) {
127 if (dst->num == 4)
128 return false;
129 dst->value[dst->num++] = src->value[i];
130 }
131
132 swizzle[i] = j;
133 }
134
135 return true;
136 }
137
ppir_update_src_pipeline(ppir_pipeline pipeline,ppir_src * src,ppir_dest * dest,uint8_t * swizzle)138 static void ppir_update_src_pipeline(ppir_pipeline pipeline, ppir_src *src,
139 ppir_dest *dest, uint8_t *swizzle)
140 {
141 if (ppir_node_target_equal(src, dest)) {
142 src->type = ppir_target_pipeline;
143 src->pipeline = pipeline;
144
145 if (swizzle) {
146 for (int k = 0; k < 4; k++)
147 src->swizzle[k] = swizzle[src->swizzle[k]];
148 }
149 }
150 }
151
152 /* make alu node src reflact the pipeline reg */
ppir_instr_update_src_pipeline(ppir_instr * instr,ppir_pipeline pipeline,ppir_dest * dest,uint8_t * swizzle)153 static void ppir_instr_update_src_pipeline(ppir_instr *instr, ppir_pipeline pipeline,
154 ppir_dest *dest, uint8_t *swizzle)
155 {
156 for (int i = PPIR_INSTR_SLOT_ALU_START; i <= PPIR_INSTR_SLOT_ALU_END; i++) {
157 if (!instr->slots[i])
158 continue;
159
160 ppir_alu_node *alu = ppir_node_to_alu(instr->slots[i]);
161 for (int j = 0; j < alu->num_src; j++) {
162 ppir_src *src = alu->src + j;
163 ppir_update_src_pipeline(pipeline, src, dest, swizzle);
164 }
165 }
166
167 ppir_node *branch_node = instr->slots[PPIR_INSTR_SLOT_BRANCH];
168 if (branch_node && (branch_node->type == ppir_node_type_branch)) {
169 ppir_branch_node *branch = ppir_node_to_branch(branch_node);
170 for (int j = 0; j < 2; j++) {
171 ppir_src *src = branch->src + j;
172 ppir_update_src_pipeline(pipeline, src, dest, swizzle);
173 }
174 }
175 }
176
ppir_instr_insert_node(ppir_instr * instr,ppir_node * node)177 bool ppir_instr_insert_node(ppir_instr *instr, ppir_node *node)
178 {
179 if (node->op == ppir_op_const) {
180 int i;
181 ppir_const_node *c = ppir_node_to_const(node);
182 const ppir_const *nc = &c->constant;
183
184 for (i = 0; i < 2; i++) {
185 ppir_const ic = instr->constant[i];
186 uint8_t swizzle[4] = {0};
187
188 if (ppir_instr_insert_const(&ic, nc, swizzle)) {
189 ppir_node *succ = ppir_node_first_succ(node);
190 ppir_src *src = NULL;
191 for (int s = 0; s < ppir_node_get_src_num(succ); s++) {
192 src = ppir_node_get_src(succ, s);
193 if (src->node == node)
194 break;
195 }
196 assert(src->node == node);
197
198 instr->constant[i] = ic;
199 ppir_update_src_pipeline(ppir_pipeline_reg_const0 + i, src,
200 &c->dest, swizzle);
201 break;
202 }
203 }
204
205 /* no const slot can insert */
206 if (i == 2)
207 return false;
208
209 return true;
210 }
211 else {
212 int *slots = ppir_op_infos[node->op].slots;
213 for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) {
214 int pos = slots[i];
215
216 if (instr->slots[pos]) {
217 /* node already in this instr, i.e. load_uniform */
218 if (instr->slots[pos] == node)
219 return true;
220 else
221 continue;
222 }
223
224 /* ^fmul dests (e.g. condition for select) can only be
225 * scheduled to ALU_SCL_MUL */
226 if (pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) {
227 ppir_dest *dest = ppir_node_get_dest(node);
228 if (dest && dest->type == ppir_target_pipeline &&
229 dest->pipeline == ppir_pipeline_reg_fmul)
230 continue;
231 }
232
233 if (pos == PPIR_INSTR_SLOT_ALU_SCL_MUL ||
234 pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) {
235 ppir_dest *dest = ppir_node_get_dest(node);
236 if (!ppir_target_is_scalar(dest))
237 continue;
238 }
239
240 instr->slots[pos] = node;
241 node->instr = instr;
242 node->instr_pos = pos;
243
244 if ((node->op == ppir_op_load_uniform) || (node->op == ppir_op_load_temp)) {
245 ppir_load_node *l = ppir_node_to_load(node);
246 ppir_instr_update_src_pipeline(
247 instr, ppir_pipeline_reg_uniform, &l->dest, NULL);
248 }
249
250 return true;
251 }
252
253 return false;
254 }
255 }
256
257 static struct {
258 int len;
259 char *name;
260 } ppir_instr_fields[] = {
261 [PPIR_INSTR_SLOT_VARYING] = { 4, "vary" },
262 [PPIR_INSTR_SLOT_TEXLD] = { 4, "texl"},
263 [PPIR_INSTR_SLOT_UNIFORM] = { 4, "unif" },
264 [PPIR_INSTR_SLOT_ALU_VEC_MUL] = { 4, "vmul" },
265 [PPIR_INSTR_SLOT_ALU_SCL_MUL] = { 4, "smul" },
266 [PPIR_INSTR_SLOT_ALU_VEC_ADD] = { 4, "vadd" },
267 [PPIR_INSTR_SLOT_ALU_SCL_ADD] = { 4, "sadd" },
268 [PPIR_INSTR_SLOT_ALU_COMBINE] = { 4, "comb" },
269 [PPIR_INSTR_SLOT_STORE_TEMP] = { 4, "stor" },
270 [PPIR_INSTR_SLOT_BRANCH] = { 4, "brch" },
271 };
272
ppir_instr_print_list(ppir_compiler * comp)273 void ppir_instr_print_list(ppir_compiler *comp)
274 {
275 if (!(lima_debug & LIMA_DEBUG_PP))
276 return;
277
278 printf("======ppir instr list======\n");
279 printf(" ");
280 for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++)
281 printf("%-*s ", ppir_instr_fields[i].len, ppir_instr_fields[i].name);
282 printf("const0|1\n");
283
284 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
285 printf("-------block %3d-------\n", block->index);
286 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
287 printf("%c%03d: ", instr->is_end ? '*' : ' ', instr->index);
288 for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
289 ppir_node *node = instr->slots[i];
290 if (node)
291 printf("%-*d ", ppir_instr_fields[i].len, node->index);
292 else
293 printf("%-*s ", ppir_instr_fields[i].len, "null");
294 }
295 for (int i = 0; i < 2; i++) {
296 if (i)
297 printf("| ");
298
299 for (int j = 0; j < instr->constant[i].num; j++)
300 printf("%f ", instr->constant[i].value[j].f);
301 }
302 printf("\n");
303 }
304 }
305 printf("===========================\n");
306 }
307
ppir_instr_print_sub(ppir_instr * instr)308 static void ppir_instr_print_sub(ppir_instr *instr)
309 {
310 printf("[%s%d",
311 instr->printed && !ppir_instr_is_leaf(instr) ? "+" : "",
312 instr->index);
313
314 if (!instr->printed) {
315 ppir_instr_foreach_pred(instr, dep) {
316 ppir_instr_print_sub(dep->pred);
317 }
318
319 instr->printed = true;
320 }
321
322 printf("]");
323 }
324
ppir_instr_print_dep(ppir_compiler * comp)325 void ppir_instr_print_dep(ppir_compiler *comp)
326 {
327 if (!(lima_debug & LIMA_DEBUG_PP))
328 return;
329
330 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
331 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
332 instr->printed = false;
333 }
334 }
335
336 printf("======ppir instr depend======\n");
337 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
338 printf("-------block %3d-------\n", block->index);
339 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
340 if (ppir_instr_is_root(instr)) {
341 ppir_instr_print_sub(instr);
342 printf("\n");
343 }
344 }
345 }
346 printf("=============================\n");
347 }
348