nv50: simple reload elimination and local CSE
[mesa.git] / src / gallium / drivers / nv50 / nv50_pc.c
1 /*
2 * Copyright 2010 Christoph Bumiller
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, 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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "nv50_pc.h"
24 #include "nv50_program.h"
25
26 #include <stdio.h>
27
28 /* returns TRUE if operands 0 and 1 can be swapped */
29 boolean
30 nv_op_commutative(uint opcode)
31 {
32 switch (opcode) {
33 case NV_OP_ADD:
34 case NV_OP_MUL:
35 case NV_OP_MAD:
36 case NV_OP_AND:
37 case NV_OP_OR:
38 case NV_OP_XOR:
39 case NV_OP_MIN:
40 case NV_OP_MAX:
41 case NV_OP_SAD:
42 return TRUE;
43 default:
44 return FALSE;
45 }
46 }
47
48 /* return operand to which the address register applies */
49 int
50 nv50_indirect_opnd(struct nv_instruction *i)
51 {
52 if (!i->src[4])
53 return -1;
54
55 switch (i->opcode) {
56 case NV_OP_MOV:
57 case NV_OP_LDA:
58 return 0;
59 default:
60 return 1;
61 }
62 }
63
64 boolean
65 nv50_nvi_can_use_imm(struct nv_instruction *nvi, int s)
66 {
67 if (nvi->flags_src || nvi->flags_def)
68 return FALSE;
69
70 switch (nvi->opcode) {
71 case NV_OP_ADD:
72 case NV_OP_MUL:
73 case NV_OP_AND:
74 case NV_OP_OR:
75 case NV_OP_XOR:
76 case NV_OP_SHL:
77 case NV_OP_SHR:
78 return (s == 1) && (nvi->def[0]->reg.file == NV_FILE_GPR);
79 case NV_OP_MOV:
80 assert(s == 0);
81 return (nvi->def[0]->reg.file == NV_FILE_GPR);
82 default:
83 return FALSE;
84 }
85 }
86
87 boolean
88 nv50_nvi_can_load(struct nv_instruction *nvi, int s, struct nv_value *value)
89 {
90 switch (nvi->opcode) {
91 case NV_OP_ABS:
92 case NV_OP_ADD:
93 case NV_OP_CEIL:
94 case NV_OP_FLOOR:
95 case NV_OP_TRUNC:
96 case NV_OP_CVT:
97 case NV_OP_MAD:
98 case NV_OP_MUL:
99 case NV_OP_SAT:
100 case NV_OP_SUB:
101 case NV_OP_MAX:
102 case NV_OP_MIN:
103 if (s == 0 && (value->reg.file == NV_FILE_MEM_S ||
104 value->reg.file == NV_FILE_MEM_P))
105 return TRUE;
106 if (s == 1 &&
107 value->reg.file >= NV_FILE_MEM_C(0) &&
108 value->reg.file <= NV_FILE_MEM_C(15))
109 return TRUE;
110 if (s == 2 && nvi->src[1]->value->reg.file == NV_FILE_GPR)
111 return TRUE;
112 return FALSE;
113 case NV_OP_MOV:
114 assert(s == 0);
115 return TRUE;
116 default:
117 return FALSE;
118 }
119 }
120
121 ubyte
122 nv50_supported_src_mods(uint opcode, int s)
123 {
124 switch (opcode) {
125 case NV_OP_ABS:
126 return NV_MOD_NEG | NV_MOD_ABS; /* obviously */
127 case NV_OP_ADD:
128 case NV_OP_MUL:
129 case NV_OP_MAD:
130 return NV_MOD_NEG;
131 case NV_OP_DFDX:
132 case NV_OP_DFDY:
133 assert(s == 0);
134 return NV_MOD_NEG;
135 case NV_OP_MAX:
136 case NV_OP_MIN:
137 return NV_MOD_ABS;
138 case NV_OP_CVT:
139 case NV_OP_LG2:
140 case NV_OP_NEG:
141 case NV_OP_PREEX2:
142 case NV_OP_PRESIN:
143 case NV_OP_RCP:
144 case NV_OP_RSQ:
145 return NV_MOD_ABS | NV_MOD_NEG;
146 default:
147 return 0;
148 }
149 }
150
151 int
152 nv_nvi_refcount(struct nv_instruction *nvi)
153 {
154 int i, rc;
155
156 rc = nvi->flags_def ? nvi->flags_def->refc : 0;
157
158 for (i = 0; i < 4; ++i) {
159 if (!nvi->def[i])
160 return rc;
161 rc += nvi->def[i]->refc;
162 }
163 return rc;
164 }
165
166 int
167 nvcg_replace_value(struct nv_pc *pc, struct nv_value *old_val,
168 struct nv_value *new_val)
169 {
170 int i, n;
171
172 if (old_val == new_val)
173 return old_val->refc;
174
175 for (i = 0, n = 0; i < pc->num_refs; ++i) {
176 if (pc->refs[i]->value == old_val) {
177 ++n;
178 nv_reference(pc, &pc->refs[i], new_val);
179 }
180 }
181 return n;
182 }
183
184 static void
185 nv_pc_free_refs(struct nv_pc *pc)
186 {
187 int i;
188 for (i = 0; i < pc->num_refs; i += 64)
189 FREE(pc->refs[i]);
190 }
191
192 void
193 nv_print_program(struct nv_basic_block *b)
194 {
195 struct nv_instruction *i = b->phi;
196
197 b->priv = 0;
198
199 debug_printf("=== BB %i ", b->id);
200 if (b->out[0])
201 debug_printf("(--0> %i) ", b->out[0]->id);
202 if (b->out[1])
203 debug_printf("(--1> %i) ", b->out[1]->id);
204 debug_printf("===\n");
205
206 if (!i)
207 i = b->entry;
208 for (; i; i = i->next)
209 nv_print_instruction(i);
210
211 if (!b->out[0]) {
212 debug_printf("END\n\n");
213 return;
214 }
215 if (!b->out[1] && ++(b->out[0]->priv) != b->out[0]->num_in)
216 return;
217
218 if (b->out[0] != b)
219 nv_print_program(b->out[0]);
220
221 if (b->out[1] && b->out[1] != b)
222 nv_print_program(b->out[1]);
223 }
224
225 static INLINE void
226 nvcg_show_bincode(struct nv_pc *pc)
227 {
228 int i;
229
230 for (i = 0; i < pc->bin_size / 4; ++i)
231 debug_printf("0x%08x ", pc->emit[i]);
232 debug_printf("\n");
233 }
234
235 static int
236 nv50_emit_program(struct nv_pc *pc)
237 {
238 uint32_t *code = pc->emit;
239 int n;
240
241 debug_printf("emitting program: size = %u\n", pc->bin_size);
242
243 for (n = 0; n < pc->num_blocks; ++n) {
244 struct nv_instruction *i;
245 struct nv_basic_block *b = pc->bb_list[n];
246
247 for (i = b->entry; i; i = i->next) {
248 nv50_emit_instruction(pc, i);
249
250 pc->bin_pos += 1 + (pc->emit[0] & 1);
251 pc->emit += 1 + (pc->emit[0] & 1);
252 }
253 }
254 assert(pc->emit == &code[pc->bin_size / 4]);
255
256 /* XXX: we can do better than this ... */
257 if ((pc->emit[-1] & 3) == 3) {
258 pc->emit[0] = 0xf0000001;
259 pc->emit[1] = 0xe0000000;
260 pc->bin_size += 8;
261 }
262
263 pc->emit = code;
264 code[pc->bin_size / 4 - 1] |= 1;
265
266 nvcg_show_bincode(pc);
267
268 return 0;
269 }
270
271 int
272 nv50_generate_code(struct nv50_translation_info *ti)
273 {
274 struct nv_pc *pc;
275 int ret;
276
277 pc = CALLOC_STRUCT(nv_pc);
278 if (!pc)
279 return 1;
280
281 ret = nv50_tgsi_to_nc(pc, ti);
282 if (ret)
283 goto out;
284
285 /* optimization */
286 ret = nv_pc_exec_pass0(pc);
287 if (ret)
288 goto out;
289
290 /* register allocation */
291 ret = nv_pc_exec_pass1(pc);
292 if (ret)
293 goto out;
294
295 /* prepare for emission */
296 ret = nv_pc_exec_pass2(pc);
297 if (ret)
298 goto out;
299
300 pc->emit = CALLOC(pc->bin_size / 4 + 2, 4);
301 if (!pc->emit) {
302 ret = 3;
303 goto out;
304 }
305 ret = nv50_emit_program(pc);
306 if (ret)
307 goto out;
308
309 ti->p->code_size = pc->bin_size;
310 ti->p->code = pc->emit;
311
312 ti->p->immd_size = pc->immd_count * 4;
313 ti->p->immd = pc->immd_buf;
314
315 ti->p->max_gpr = (pc->max_reg[NV_FILE_GPR] + 1) >> 1;
316 ti->p->max_gpr++;
317
318 ti->p->fixups = pc->fixups;
319 ti->p->num_fixups = pc->num_fixups;
320
321 debug_printf("SHADER TRANSLATION - %s\n", ret ? "failure" : "success");
322
323 out:
324 nv_pc_free_refs(pc);
325 if (ret) {
326 if (pc->emit)
327 free(pc->emit);
328 if (pc->immd_buf)
329 free(pc->immd_buf);
330 if (pc->fixups)
331 free(pc->fixups);
332 }
333 free(pc);
334
335 return ret;
336 }
337
338 static void
339 nvbb_insert_phi(struct nv_basic_block *b, struct nv_instruction *i)
340 {
341 if (!b->phi) {
342 i->prev = NULL;
343 b->phi = i;
344 i->next = b->entry;
345 if (b->entry) {
346 assert(!b->entry->prev && b->exit);
347 b->entry->prev = i;
348 } else {
349 b->entry = i;
350 b->exit = i;
351 }
352 } else {
353 assert(b->entry);
354 if (b->entry->opcode == NV_OP_PHI) { /* insert after entry */
355 assert(b->entry == b->exit);
356 b->entry->next = i;
357 i->prev = b->entry;
358 b->entry = i;
359 b->exit = i;
360 } else { /* insert before entry */
361 assert(b->entry->prev && b->exit);
362 i->next = b->entry;
363 i->prev = b->entry->prev;
364 b->entry->prev = i;
365 i->prev->next = i;
366 }
367 }
368 }
369
370 void
371 nvbb_insert_tail(struct nv_basic_block *b, struct nv_instruction *i)
372 {
373 if (i->opcode == NV_OP_PHI) {
374 nvbb_insert_phi(b, i);
375 } else {
376 i->prev = b->exit;
377 if (b->exit)
378 b->exit->next = i;
379 b->exit = i;
380 if (!b->entry)
381 b->entry = i;
382 else
383 if (i->prev && i->prev->opcode == NV_OP_PHI)
384 b->entry = i;
385 }
386
387 i->bb = b;
388 b->num_instructions++;
389 }
390
391 void
392 nv_nvi_delete(struct nv_instruction *nvi)
393 {
394 struct nv_basic_block *b = nvi->bb;
395 int j;
396
397 debug_printf("REM: "); nv_print_instruction(nvi);
398
399 for (j = 0; j < 4; ++j) {
400 if (!nvi->src[j])
401 break;
402 --(nvi->src[j]->value->refc);
403 nvi->src[j] = NULL;
404 }
405
406 if (nvi->next)
407 nvi->next->prev = nvi->prev;
408 else {
409 assert(nvi == b->exit);
410 b->exit = nvi->prev;
411 }
412
413 if (nvi->prev)
414 nvi->prev->next = nvi->next;
415
416 if (nvi == b->entry) {
417 assert(nvi->opcode != NV_OP_PHI || !nvi->next);
418
419 if (!nvi->next || (nvi->opcode == NV_OP_PHI))
420 b->entry = nvi->prev;
421 else
422 b->entry = nvi->next;
423 }
424
425 if (nvi == b->phi) {
426 assert(!nvi->prev);
427 if (nvi->opcode != NV_OP_PHI)
428 debug_printf("WARN: b->phi points to non-PHI instruction\n");
429
430 if (!nvi->next || nvi->next->opcode != NV_OP_PHI)
431 b->phi = NULL;
432 else
433 b->phi = nvi->next;
434 }
435 }
436
437 void
438 nv_nvi_permute(struct nv_instruction *i1, struct nv_instruction *i2)
439 {
440 struct nv_basic_block *b = i1->bb;
441
442 assert(i1->opcode != NV_OP_PHI &&
443 i2->opcode != NV_OP_PHI);
444 assert(i1->next == i2);
445
446 if (b->exit == i2)
447 b->exit = i1;
448
449 if (b->entry == i1)
450 b->entry = i2;
451
452 i2->prev = i1->prev;
453 i1->next = i2->next;
454 i2->next = i1;
455 i1->prev = i2;
456
457 if (i2->prev)
458 i2->prev->next = i2;
459 if (i1->next)
460 i1->next->prev = i1;
461 }
462
463 void nvbb_attach_block(struct nv_basic_block *parent, struct nv_basic_block *b)
464 {
465 if (parent->out[0]) {
466 assert(!parent->out[1]);
467 parent->out[1] = b;
468 } else
469 parent->out[0] = b;
470
471 b->in[b->num_in++] = parent;
472 }