r600g/sb: use hex instead of binary constants
[mesa.git] / src / gallium / drivers / r600 / sb / sb_bc_parser.cpp
1 /*
2 * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com>
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
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
13 * 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 AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Vadim Girlin
25 */
26
27 #define BCP_DEBUG 0
28
29 #if BCP_DEBUG
30 #define BCP_DUMP(q) do { q } while (0)
31 #else
32 #define BCP_DUMP(q)
33 #endif
34
35 extern "C" {
36 #include "r600_pipe.h"
37 #include "r600_shader.h"
38 }
39
40 #include <stack>
41
42 #include "sb_bc.h"
43 #include "sb_shader.h"
44 #include "sb_pass.h"
45
46 namespace r600_sb {
47
48 using std::cerr;
49
50 int bc_parser::parse() {
51
52 dw = bc->bytecode;
53 bc_ndw = bc->ndw;
54 max_cf = 0;
55
56 dec = new bc_decoder(ctx, dw, bc_ndw);
57
58 shader_target t = TARGET_UNKNOWN;
59
60 if (pshader) {
61 switch (bc->type) {
62 case TGSI_PROCESSOR_FRAGMENT: t = TARGET_PS; break;
63 case TGSI_PROCESSOR_VERTEX: t = TARGET_VS; break;
64 case TGSI_PROCESSOR_COMPUTE: t = TARGET_COMPUTE; break;
65 default: assert(!"unknown shader target"); return -1; break;
66 }
67 } else {
68 if (bc->type == TGSI_PROCESSOR_COMPUTE)
69 t = TARGET_COMPUTE;
70 else
71 t = TARGET_FETCH;
72 }
73
74 sh = new shader(ctx, t, bc->debug_id, enable_dump);
75 int r = parse_shader();
76
77 if (r)
78 return r;
79
80 sh->ngpr = bc->ngpr;
81 sh->nstack = bc->nstack;
82
83 if (sh->target != TARGET_FETCH) {
84 sh->src_stats.ndw = bc->ndw;
85 sh->collect_stats(false);
86 }
87
88 if (enable_dump) {
89 bc_dump(*sh, cerr, bc->bytecode, bc_ndw).run();
90 }
91
92 if (!optimize)
93 return 0;
94
95 prepare_ir();
96
97 delete dec;
98 return r;
99 }
100
101 int bc_parser::parse_shader() {
102 int r = 0;
103 unsigned i = 0;
104 bool eop = false;
105
106 sh->init();
107
108 if (pshader)
109 parse_decls();
110
111 do {
112 eop = false;
113 if ((r = parse_cf(i, eop)))
114 return r;
115
116 } while (!eop || (i >> 1) <= max_cf);
117
118 return 0;
119 }
120
121 int bc_parser::parse_decls() {
122
123 // sh->prepare_regs(rs.bc.ngpr);
124
125 if (pshader->indirect_files & ~(1 << TGSI_FILE_CONSTANT)) {
126
127 #if SB_NO_ARRAY_INFO
128
129 sh->add_gpr_array(0, pshader->bc.ngpr, 0x0F);
130
131 #else
132
133 assert(pshader->num_arrays);
134
135 if (pshader->num_arrays) {
136
137 for (unsigned i = 0; i < pshader->num_arrays; ++i) {
138 r600_shader_array &a = pshader->arrays[i];
139 sh->add_gpr_array(a.gpr_start, a.gpr_count, a.comp_mask);
140 }
141
142 } else {
143 sh->add_gpr_array(0, pshader->bc.ngpr, 0x0F);
144 }
145
146
147 #endif
148
149 }
150
151 if (sh->target == TARGET_VS)
152 sh->add_input(0, 1, 0x0F);
153
154 bool ps_interp = ctx.hw_class >= HW_CLASS_EVERGREEN
155 && sh->target == TARGET_PS;
156
157 unsigned linear = 0, persp = 0, centroid = 1;
158
159 for (unsigned i = 0; i < pshader->ninput; ++i) {
160 r600_shader_io & in = pshader->input[i];
161 bool preloaded = sh->target == TARGET_PS && !(ps_interp && in.spi_sid);
162 sh->add_input(in.gpr, preloaded, /*in.write_mask*/ 0x0F);
163 if (ps_interp && in.spi_sid) {
164 if (in.interpolate == TGSI_INTERPOLATE_LINEAR ||
165 in.interpolate == TGSI_INTERPOLATE_COLOR)
166 linear = 1;
167 else if (in.interpolate == TGSI_INTERPOLATE_PERSPECTIVE)
168 persp = 1;
169 if (in.centroid)
170 centroid = 2;
171 }
172 }
173
174 if (ps_interp) {
175 unsigned mask = (1 << (2 * (linear + persp) * centroid)) - 1;
176 unsigned gpr = 0;
177
178 while (mask) {
179 sh->add_input(gpr, true, mask & 0x0F);
180 ++gpr;
181 mask >>= 4;
182 }
183 }
184
185
186 return 0;
187 }
188
189
190 int bc_parser::parse_cf(unsigned &i, bool &eop) {
191
192 int r;
193
194 cf_node *cf = sh->create_cf();
195 sh->root->push_back(cf);
196
197 unsigned id = i >> 1;
198
199 cf->bc.id = id;
200
201 if (cf_map.size() < id + 1)
202 cf_map.resize(id + 1);
203
204 cf_map[id] = cf;
205
206 if ((r = dec->decode_cf(i, cf->bc)))
207 return r;
208
209 cf_op_flags flags = (cf_op_flags)cf->bc.op_ptr->flags;
210
211 if (flags & CF_ALU) {
212 if ((r = parse_alu_clause(cf)))
213 return r;
214 } else if (flags & CF_FETCH) {
215 if ((r = parse_fetch_clause(cf)))
216 return r;;
217 } else if (flags & CF_EXP) {
218 assert(!cf->bc.rw_rel);
219 } else if (flags & (CF_STRM | CF_RAT)) {
220 assert(!cf->bc.rw_rel);
221 } else if (cf->bc.op == CF_OP_CALL_FS) {
222 sh->init_call_fs(cf);
223 cf->flags |= NF_SCHEDULE_EARLY | NF_DONT_MOVE;
224 } else if (flags & CF_BRANCH) {
225 if (cf->bc.addr > max_cf)
226 max_cf = cf->bc.addr;
227 }
228
229 eop = cf->bc.end_of_program || cf->bc.op == CF_OP_CF_END ||
230 cf->bc.op == CF_OP_RET;
231 return 0;
232 }
233
234 int bc_parser::parse_alu_clause(cf_node* cf) {
235 unsigned i = cf->bc.addr << 1, cnt = cf->bc.count + 1, gcnt;
236
237 cf->subtype = NST_ALU_CLAUSE;
238
239 cgroup = 0;
240 memset(slots[0], 0, 5*sizeof(slots[0][0]));
241
242 unsigned ng = 0;
243
244 do {
245 parse_alu_group(cf, i, gcnt);
246 assert(gcnt <= cnt);
247 cnt -= gcnt;
248 ng++;
249 } while (cnt);
250
251 return 0;
252 }
253
254 int bc_parser::parse_alu_group(cf_node* cf, unsigned &i, unsigned &gcnt) {
255 int r;
256 alu_node *n;
257 alu_group_node *g = sh->create_alu_group();
258
259 cgroup = !cgroup;
260 memset(slots[cgroup], 0, 5*sizeof(slots[0][0]));
261
262 gcnt = 0;
263
264 do {
265 n = sh->create_alu();
266 g->push_back(n);
267
268 if ((r = dec->decode_alu(i, n->bc)))
269 return r;
270
271 if (!sh->assign_slot(n, slots[cgroup])) {
272 assert(!"alu slot assignment failed");
273 return -1;
274 }
275
276 gcnt++;
277
278 } while (gcnt <= 5 && !n->bc.last);
279
280 assert(n->bc.last);
281
282 unsigned literal_mask = 0;
283
284 for (node_iterator I = g->begin(), E = g->end();
285 I != E; ++I) {
286 n = static_cast<alu_node*>(*I);
287 unsigned src_count = n->bc.op_ptr->src_count;
288
289 if (ctx.alu_slots(n->bc.op) & AF_4SLOT)
290 n->flags |= NF_ALU_4SLOT;
291
292 n->src.resize(src_count);
293
294 unsigned flags = n->bc.op_ptr->flags;
295
296 if (flags & AF_PRED) {
297 n->dst.resize(3);
298 if (n->bc.update_pred)
299 n->dst[1] = sh->get_special_value(SV_ALU_PRED);
300 if (n->bc.update_exec_mask)
301 n->dst[2] = sh->get_special_value(SV_EXEC_MASK);
302
303 n->flags |= NF_DONT_HOIST;
304
305 } else if (flags & AF_KILL) {
306
307 n->dst.resize(2);
308 n->dst[1] = sh->get_special_value(SV_VALID_MASK);
309 sh->set_uses_kill();
310
311 n->flags |= NF_DONT_HOIST | NF_DONT_MOVE |
312 NF_DONT_KILL | NF_SCHEDULE_EARLY;
313
314 } else {
315 n->dst.resize(1);
316 }
317
318 if (flags & AF_MOVA) {
319
320 n->dst[0] = sh->get_special_value(SV_AR_INDEX);
321
322 n->flags |= NF_DONT_HOIST;
323
324 } else if (n->bc.op_ptr->src_count == 3 || n->bc.write_mask) {
325 assert(!n->bc.dst_rel || n->bc.index_mode == INDEX_AR_X);
326
327 value *v = sh->get_gpr_value(false, n->bc.dst_gpr, n->bc.dst_chan,
328 n->bc.dst_rel);
329
330 n->dst[0] = v;
331 }
332
333 if (n->bc.pred_sel) {
334 sh->has_alu_predication = true;
335 n->pred = sh->get_special_value(SV_ALU_PRED);
336 }
337
338 for (unsigned s = 0; s < src_count; ++s) {
339 bc_alu_src &src = n->bc.src[s];
340
341 if (src.sel == ALU_SRC_LITERAL) {
342 unsigned chan = src.chan;
343
344 literal_mask |= (1 << chan);
345 src.value.u = dw[i+chan];
346 n->src[s] = sh->get_const_value(src.value);
347 } else if (src.sel == ALU_SRC_PS || src.sel == ALU_SRC_PV) {
348 unsigned pgroup = !cgroup, prev_slot = src.sel == ALU_SRC_PS ?
349 SLOT_TRANS : src.chan;
350 alu_node *prev_alu = slots[pgroup][prev_slot];
351
352 assert(prev_alu);
353
354 if (!prev_alu->dst[0]) {
355 value * t = sh->create_temp_value();
356 prev_alu->dst[0] = t;
357 }
358
359 value *d = prev_alu->dst[0];
360
361 if (d->is_rel()) {
362 d = sh->get_gpr_value(true, prev_alu->bc.dst_gpr,
363 prev_alu->bc.dst_chan,
364 prev_alu->bc.dst_rel);
365 }
366
367 n->src[s] = d;
368 } else if (ctx.is_kcache_sel(src.sel)) {
369 unsigned sel = src.sel, kc_addr;
370 unsigned kc_set = ((sel >> 7) & 2) + ((sel >> 5) & 1);
371
372 bc_kcache &kc = cf->bc.kc[kc_set];
373 kc_addr = (kc.addr << 4) + (sel & 0x1F);
374 n->src[s] = sh->get_kcache_value(kc.bank, kc_addr, src.chan);
375 } else if (src.sel < MAX_GPR) {
376 value *v = sh->get_gpr_value(true, src.sel, src.chan, src.rel);
377
378 n->src[s] = v;
379
380 } else if (src.sel >= ALU_SRC_PARAM_OFFSET) {
381 // using slot for value channel because in fact the slot
382 // determines the channel that is loaded by INTERP_LOAD_P0
383 // (and maybe some others).
384 // otherwise GVN will consider INTERP_LOAD_P0s with the same
385 // param index as equal instructions and leave only one of them
386 n->src[s] = sh->get_special_ro_value(sel_chan(src.sel,
387 n->bc.slot));
388 } else {
389 switch (src.sel) {
390 case ALU_SRC_0:
391 n->src[s] = sh->get_const_value(0);
392 break;
393 case ALU_SRC_0_5:
394 n->src[s] = sh->get_const_value(0.5f);
395 break;
396 case ALU_SRC_1:
397 n->src[s] = sh->get_const_value(1.0f);
398 break;
399 case ALU_SRC_1_INT:
400 n->src[s] = sh->get_const_value(1);
401 break;
402 case ALU_SRC_M_1_INT:
403 n->src[s] = sh->get_const_value(-1);
404 break;
405 default:
406 n->src[s] = sh->get_special_ro_value(src.sel);
407 break;
408 }
409 }
410 }
411 }
412
413 // pack multislot instructions into alu_packed_node
414
415 alu_packed_node *p = NULL;
416 for (node_iterator N, I = g->begin(), E = g->end(); I != E; I = N) {
417 N = I + 1;
418 alu_node *a = static_cast<alu_node*>(*I);
419 unsigned sflags = a->bc.slot_flags;
420
421 if (sflags == AF_4V || (ctx.is_cayman() && sflags == AF_S)) {
422 if (!p)
423 p = sh->create_alu_packed();
424
425 a->remove();
426 p->push_back(a);
427 }
428 }
429
430 if (p) {
431 g->push_front(p);
432 }
433
434 unsigned literal_ndw = 0;
435 while (literal_mask) {
436 g->literals.push_back(dw[i + literal_ndw]);
437 literal_ndw += 1;
438 literal_mask >>= 1;
439 }
440
441 literal_ndw = (literal_ndw + 1) & ~1u;
442
443 i += literal_ndw;
444 gcnt += literal_ndw >> 1;
445
446 cf->push_back(g);
447 return 0;
448 }
449
450 int bc_parser::parse_fetch_clause(cf_node* cf) {
451 int r;
452 unsigned i = cf->bc.addr << 1, cnt = cf->bc.count + 1;
453
454 cf->subtype = NST_TEX_CLAUSE;
455
456 vvec grad_v, grad_h;
457
458 while (cnt--) {
459 fetch_node *n = sh->create_fetch();
460 cf->push_back(n);
461 if ((r = dec->decode_fetch(i, n->bc)))
462 return r;
463
464 unsigned flags = n->bc.op_ptr->flags;
465
466 unsigned vtx = flags & FF_VTX;
467 unsigned num_src = vtx ? ctx.vtx_src_num : 4;
468
469 n->dst.resize(4);
470
471 if (flags & (FF_SETGRAD | FF_USEGRAD | FF_GETGRAD)) {
472 sh->uses_gradients = true;
473 }
474
475 if (flags & FF_SETGRAD) {
476
477 vvec *grad = NULL;
478
479 switch (n->bc.op) {
480 case FETCH_OP_SET_GRADIENTS_V:
481 grad = &grad_v;
482 break;
483 case FETCH_OP_SET_GRADIENTS_H:
484 grad = &grad_h;
485 break;
486 default:
487 assert(!"unexpected SET_GRAD instruction");
488 return -1;
489 }
490
491 if (grad->empty())
492 grad->resize(4);
493
494 for(unsigned s = 0; s < 4; ++s) {
495 unsigned sw = n->bc.src_sel[s];
496 if (sw <= SEL_W)
497 (*grad)[s] = sh->get_gpr_value(true, n->bc.src_gpr,
498 sw, false);
499 else if (sw == SEL_0)
500 (*grad)[s] = sh->get_const_value(0.0f);
501 else if (sw == SEL_1)
502 (*grad)[s] = sh->get_const_value(1.0f);
503 }
504 } else {
505
506 if (flags & FF_USEGRAD) {
507 n->src.resize(12);
508 std::copy(grad_v.begin(), grad_v.end(), n->src.begin() + 4);
509 std::copy(grad_h.begin(), grad_h.end(), n->src.begin() + 8);
510 } else {
511 n->src.resize(4);
512 }
513
514 for(int s = 0; s < 4; ++s) {
515 if (n->bc.dst_sel[s] != SEL_MASK)
516 n->dst[s] = sh->get_gpr_value(false, n->bc.dst_gpr, s, false);
517 // NOTE: it doesn't matter here which components of the result we
518 // are using, but original n->bc.dst_sel should be taken into
519 // account when building the bytecode
520 }
521 for(unsigned s = 0; s < num_src; ++s) {
522 if (n->bc.src_sel[s] <= SEL_W)
523 n->src[s] = sh->get_gpr_value(true, n->bc.src_gpr,
524 n->bc.src_sel[s], false);
525 }
526
527 }
528 }
529 return 0;
530 }
531
532 int bc_parser::prepare_ir() {
533
534 for(id_cf_map::iterator I = cf_map.begin(), E = cf_map.end(); I != E; ++I) {
535 cf_node *c = *I;
536
537 if (!c)
538 continue;
539
540 unsigned flags = c->bc.op_ptr->flags;
541
542 if (flags & CF_LOOP_START) {
543 prepare_loop(c);
544 } else if (c->bc.op == CF_OP_JUMP) {
545 prepare_if(c);
546 } else if (c->bc.op == CF_OP_LOOP_END) {
547 loop_stack.pop();
548 } else if (c->bc.op == CF_OP_LOOP_CONTINUE) {
549 assert(!loop_stack.empty());
550 repeat_node *rep = sh->create_repeat(loop_stack.top());
551 if (c->parent->first != c)
552 rep->move(c->parent->first, c);
553 c->replace_with(rep);
554 sh->simplify_dep_rep(rep);
555 } else if (c->bc.op == CF_OP_LOOP_BREAK) {
556 assert(!loop_stack.empty());
557 depart_node *dep = sh->create_depart(loop_stack.top());
558 if (c->parent->first != c)
559 dep->move(c->parent->first, c);
560 c->replace_with(dep);
561 sh->simplify_dep_rep(dep);
562 } else if (flags & CF_ALU && ctx.is_cayman()) {
563 // postprocess cayman's 3-slot instructions (ex-trans-only)
564 // FIXME it shouldn't be required with proper handling
565 prepare_alu_clause(c);
566 } else if (flags & CF_EXP) {
567
568 // unroll burst exports
569
570 assert(c->bc.op == CF_OP_EXPORT || c->bc.op == CF_OP_EXPORT_DONE);
571
572 c->bc.set_op(CF_OP_EXPORT);
573
574 unsigned burst_count = c->bc.burst_count;
575 unsigned eop = c->bc.end_of_program;
576
577 c->bc.end_of_program = 0;
578 c->bc.burst_count = 0;
579
580 do {
581 c->src.resize(4);
582
583 for(int s = 0; s < 4; ++s) {
584 switch (c->bc.sel[s]) {
585 case SEL_0:
586 c->src[s] = sh->get_const_value(0.0f);
587 break;
588 case SEL_1:
589 c->src[s] = sh->get_const_value(1.0f);
590 break;
591 case SEL_MASK:
592 break;
593 default:
594 if (c->bc.sel[s] <= SEL_W)
595 c->src[s] = sh->get_gpr_value(true, c->bc.rw_gpr,
596 c->bc.sel[s], false);
597 else
598 assert(!"invalid src_sel for export");
599 }
600 }
601
602 if (!burst_count--)
603 break;
604
605 cf_node *cf_next = sh->create_cf();
606 cf_next->bc = c->bc;
607 ++cf_next->bc.rw_gpr;
608 ++cf_next->bc.array_base;
609
610 c->insert_after(cf_next);
611 c = cf_next;
612
613 } while (1);
614
615 c->bc.end_of_program = eop;
616 } else if (flags & (CF_STRM | CF_RAT)) {
617
618 unsigned burst_count = c->bc.burst_count;
619 unsigned eop = c->bc.end_of_program;
620
621 c->bc.end_of_program = 0;
622 c->bc.burst_count = 0;
623
624 do {
625
626 c->src.resize(4);
627
628 for(int s = 0; s < 4; ++s) {
629 if (c->bc.comp_mask & (1 << s))
630 c->src[s] =
631 sh->get_gpr_value(true, c->bc.rw_gpr, s, false);
632 }
633
634 if ((flags & CF_RAT) && (c->bc.type & 1)) { // indexed write
635 c->src.resize(8);
636 for(int s = 0; s < 3; ++s) {
637 c->src[4 + s] =
638 sh->get_gpr_value(true, c->bc.index_gpr, s, false);
639 }
640
641 // FIXME probably we can relax it a bit
642 c->flags |= NF_DONT_HOIST | NF_DONT_MOVE;
643 }
644
645 if (!burst_count--)
646 break;
647
648 cf_node *cf_next = sh->create_cf();
649 cf_next->bc = c->bc;
650 ++cf_next->bc.rw_gpr;
651
652 // FIXME is it correct?
653 cf_next->bc.array_base += cf_next->bc.elem_size + 1;
654
655 c->insert_after(cf_next);
656 c = cf_next;
657 } while (1);
658
659 c->bc.end_of_program = eop;
660
661 }
662 }
663
664 assert(loop_stack.empty());
665 return 0;
666 }
667
668 int bc_parser::prepare_loop(cf_node* c) {
669
670 cf_node *end = cf_map[c->bc.addr - 1];
671 assert(end->bc.op == CF_OP_LOOP_END);
672 assert(c->parent == end->parent);
673
674 region_node *reg = sh->create_region();
675 repeat_node *rep = sh->create_repeat(reg);
676
677 reg->push_back(rep);
678 c->insert_before(reg);
679 rep->move(c, end->next);
680
681 loop_stack.push(reg);
682 return 0;
683 }
684
685 int bc_parser::prepare_if(cf_node* c) {
686 cf_node *c_else = NULL, *end = cf_map[c->bc.addr];
687
688 BCP_DUMP(
689 cerr << "parsing JUMP @" << c->bc.id;
690 cerr << "\n";
691 );
692
693 if (end->bc.op == CF_OP_ELSE) {
694 BCP_DUMP(
695 cerr << " found ELSE : ";
696 dump::dump_op(end);
697 cerr << "\n";
698 );
699
700 c_else = end;
701 end = cf_map[c_else->bc.addr];
702 } else {
703 BCP_DUMP(
704 cerr << " no else\n";
705 );
706
707 c_else = end;
708 }
709
710 if (c_else->parent != c->parent)
711 c_else = NULL;
712
713 if (end->parent != c->parent)
714 end = NULL;
715
716 region_node *reg = sh->create_region();
717
718 depart_node *dep2 = sh->create_depart(reg);
719 depart_node *dep = sh->create_depart(reg);
720 if_node *n_if = sh->create_if();
721
722 c->insert_before(reg);
723
724 if (c_else != end)
725 dep->move(c_else, end);
726 dep2->move(c, end);
727
728 reg->push_back(dep);
729 dep->push_front(n_if);
730 n_if->push_back(dep2);
731
732 n_if->cond = sh->get_special_value(SV_EXEC_MASK);
733
734 return 0;
735 }
736
737 int bc_parser::prepare_alu_clause(cf_node* c) {
738
739 // loop over alu groups
740 for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
741 assert(I->subtype == NST_ALU_GROUP);
742
743 alu_group_node *g = static_cast<alu_group_node*>(*I);
744
745 // loop over alu_group items
746 for (node_iterator I2 = g->begin(), E2 = g->end(); I2 != E2; ++I2) {
747 if (I2->subtype != NST_ALU_PACKED_INST)
748 continue;
749
750 alu_packed_node *p = static_cast<alu_packed_node*>(*I2);
751
752 if (p->count() == 3) {
753 // cayman's scalar instruction that takes 3 or 4 slots
754
755 // FIXME for simplicity we'll always add 4th slot,
756 // but probably we might want to always remove 4th slot and make
757 // sure that regalloc won't choose w component for dst
758
759 alu_node *f = static_cast<alu_node*>(p->first);
760 alu_node *a = sh->create_alu();
761 a->src = f->src;
762 a->dst.resize(f->dst.size());
763 a->bc = f->bc;
764 a->bc.slot = SLOT_W;
765 p->push_back(a);
766 }
767 }
768 }
769
770 return 0;
771 }
772
773 } // namespace r600_sb