r600g/sb: initial commit of the optimizing shader backend
[mesa.git] / src / gallium / drivers / r600 / sb / sb_bc_finalize.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 FBC_DEBUG 0
28
29 #if FBC_DEBUG
30 #define FBC_DUMP(q) do { q } while (0)
31 #else
32 #define FBC_DUMP(q)
33 #endif
34
35 #include <iostream>
36
37 #include "sb_bc.h"
38
39 #include "sb_shader.h"
40
41 #include "sb_pass.h"
42
43 namespace r600_sb {
44
45 using std::cerr;
46
47 int bc_finalizer::run() {
48
49 regions_vec &rv = sh.get_regions();
50
51 for (regions_vec::reverse_iterator I = rv.rbegin(), E = rv.rend(); I != E;
52 ++I) {
53 region_node *r = *I;
54
55 assert(r);
56
57 bool loop = r->is_loop();
58
59 if (loop)
60 finalize_loop(r);
61 else
62 finalize_if(r);
63
64 r->expand();
65 }
66
67 run_on(sh.root);
68
69 cf_peephole();
70
71 // workaround for some problems on r6xx/7xx
72 // add ALU NOP to each vertex shader
73 if (!ctx.is_egcm() && sh.target == TARGET_VS) {
74 cf_node *c = sh.create_clause(NST_ALU_CLAUSE);
75
76 alu_group_node *g = sh.create_alu_group();
77
78 alu_node *a = sh.create_alu();
79 a->bc.set_op(ALU_OP0_NOP);
80 a->bc.last = 1;
81
82 g->push_back(a);
83 c->push_back(g);
84
85 sh.root->push_back(c);
86
87 c = sh.create_cf(CF_OP_NOP);
88 sh.root->push_back(c);
89
90 last_cf = c;
91 }
92
93 if (last_cf->bc.op_ptr->flags & CF_ALU) {
94 last_cf = sh.create_cf(CF_OP_NOP);
95 sh.root->push_back(last_cf);
96 }
97
98 if (ctx.is_cayman())
99 last_cf->insert_after(sh.create_cf(CF_OP_CF_END));
100 else
101 last_cf->bc.end_of_program = 1;
102
103 for (unsigned t = EXP_PIXEL; t < EXP_TYPE_COUNT; ++t) {
104 cf_node *le = last_export[t];
105 if (le)
106 le->bc.set_op(CF_OP_EXPORT_DONE);
107 }
108
109 sh.ngpr = ngpr;
110 sh.nstack = nstack;
111 return 0;
112 }
113
114 void bc_finalizer::finalize_loop(region_node* r) {
115
116 cf_node *loop_start = sh.create_cf(CF_OP_LOOP_START_DX10);
117 cf_node *loop_end = sh.create_cf(CF_OP_LOOP_END);
118
119 loop_start->jump_after(loop_end);
120 loop_end->jump_after(loop_start);
121
122 for (depart_vec::iterator I = r->departs.begin(), E = r->departs.end();
123 I != E; ++I) {
124 depart_node *dep = *I;
125 cf_node *loop_break = sh.create_cf(CF_OP_LOOP_BREAK);
126 loop_break->jump(loop_end);
127 dep->push_back(loop_break);
128 dep->expand();
129 }
130
131 // FIXME produces unnecessary LOOP_CONTINUE
132 for (repeat_vec::iterator I = r->repeats.begin(), E = r->repeats.end();
133 I != E; ++I) {
134 repeat_node *rep = *I;
135 if (!(rep->parent == r && rep->prev == NULL)) {
136 cf_node *loop_cont = sh.create_cf(CF_OP_LOOP_CONTINUE);
137 loop_cont->jump(loop_end);
138 rep->push_back(loop_cont);
139 }
140 rep->expand();
141 }
142
143 r->push_front(loop_start);
144 r->push_back(loop_end);
145 }
146
147 void bc_finalizer::finalize_if(region_node* r) {
148
149 update_nstack(r);
150
151 // expecting the following control flow structure here:
152 // - region
153 // {
154 // - depart/repeat 1 (it may be depart/repeat for some outer region)
155 // {
156 // - if
157 // {
158 // - depart/repeat 2 (possibly for outer region)
159 // {
160 // - some optional code
161 // }
162 // }
163 // - optional <else> code> ...
164 // }
165 // }
166
167 container_node *repdep1 = static_cast<container_node*>(r->first);
168 assert(repdep1->is_depart() || repdep1->is_repeat());
169
170 if_node *n_if = static_cast<if_node*>(repdep1->first);
171
172 if (n_if) {
173
174
175 assert(n_if->is_if());
176
177 container_node *repdep2 = static_cast<container_node*>(n_if->first);
178 assert(repdep2->is_depart() || repdep2->is_repeat());
179
180 cf_node *if_jump = sh.create_cf(CF_OP_JUMP);
181 cf_node *if_pop = sh.create_cf(CF_OP_POP);
182
183 if_pop->bc.pop_count = 1;
184 if_pop->jump_after(if_pop);
185
186 r->push_front(if_jump);
187 r->push_back(if_pop);
188
189 bool has_else = n_if->next;
190
191 if (has_else) {
192 cf_node *nelse = sh.create_cf(CF_OP_ELSE);
193 n_if->insert_after(nelse);
194 if_jump->jump(nelse);
195 nelse->jump_after(if_pop);
196 nelse->bc.pop_count = 1;
197
198 } else {
199 if_jump->jump_after(if_pop);
200 if_jump->bc.pop_count = 1;
201 }
202
203 n_if->expand();
204 }
205
206 for (depart_vec::iterator I = r->departs.begin(), E = r->departs.end();
207 I != E; ++I) {
208 (*I)->expand();
209 }
210 r->departs.clear();
211 assert(r->repeats.empty());
212 }
213
214 void bc_finalizer::run_on(container_node* c) {
215
216 for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
217 node *n = *I;
218
219 if (n->is_alu_group()) {
220 finalize_alu_group(static_cast<alu_group_node*>(n));
221 } else {
222 if (n->is_fetch_inst()) {
223 finalize_fetch(static_cast<fetch_node*>(n));
224 } else if (n->is_cf_inst()) {
225 finalize_cf(static_cast<cf_node*>(n));
226 } else if (n->is_alu_clause()) {
227
228 } else if (n->is_fetch_clause()) {
229
230 } else {
231 assert(!"unexpected node");
232 }
233
234 if (n->is_container())
235 run_on(static_cast<container_node*>(n));
236 }
237 }
238 }
239
240 void bc_finalizer::finalize_alu_group(alu_group_node* g) {
241
242 alu_node *last = NULL;
243
244 for (node_iterator I = g->begin(), E = g->end(); I != E; ++I) {
245 alu_node *n = static_cast<alu_node*>(*I);
246 unsigned slot = n->bc.slot;
247
248 value *d = n->dst.empty() ? NULL : n->dst[0];
249
250 if (d && d->is_special_reg()) {
251 assert(n->bc.op_ptr->flags & AF_MOVA);
252 d = NULL;
253 }
254
255 sel_chan fdst = d ? d->get_final_gpr() : sel_chan(0, 0);
256
257 if (d) {
258 assert(fdst.chan() == slot || slot == SLOT_TRANS);
259 }
260
261 n->bc.dst_gpr = fdst.sel();
262 n->bc.dst_chan = d ? fdst.chan() : slot < SLOT_TRANS ? slot : 0;
263
264
265 if (d && d->is_rel() && d->rel && !d->rel->is_const()) {
266 n->bc.dst_rel = 1;
267 update_ngpr(d->array->gpr.sel() + d->array->array_size -1);
268 } else {
269 n->bc.dst_rel = 0;
270 }
271
272 n->bc.write_mask = d != NULL;
273 n->bc.last = 0;
274
275 if (n->bc.op_ptr->flags & AF_PRED) {
276 n->bc.update_pred = (n->dst[1] != NULL);
277 n->bc.update_exec_mask = (n->dst[2] != NULL);
278 }
279
280 // FIXME handle predication here
281 n->bc.pred_sel = PRED_SEL_OFF;
282
283 update_ngpr(n->bc.dst_gpr);
284
285 finalize_alu_src(g, n);
286
287 last = n;
288 }
289
290 last->bc.last = 1;
291 }
292
293 void bc_finalizer::finalize_alu_src(alu_group_node* g, alu_node* a) {
294 vvec &sv = a->src;
295
296 FBC_DUMP(
297 cerr << "finalize_alu_src: ";
298 dump::dump_op(a);
299 cerr << "\n";
300 );
301
302 unsigned si = 0;
303
304 for (vvec::iterator I = sv.begin(), E = sv.end(); I != E; ++I, ++si) {
305 value *v = *I;
306 assert(v);
307
308 bc_alu_src &src = a->bc.src[si];
309 sel_chan sc;
310 src.rel = 0;
311
312 sel_chan gpr;
313
314 switch (v->kind) {
315 case VLK_REL_REG:
316 sc = v->get_final_gpr();
317 src.sel = sc.sel();
318 src.chan = sc.chan();
319 if (!v->rel->is_const()) {
320 src.rel = 1;
321 update_ngpr(v->array->gpr.sel() + v->array->array_size -1);
322 } else
323 src.rel = 0;
324
325 break;
326 case VLK_REG:
327 gpr = v->get_final_gpr();
328 src.sel = gpr.sel();
329 src.chan = gpr.chan();
330 update_ngpr(src.sel);
331 break;
332 case VLK_TEMP:
333 src.sel = v->gpr.sel();
334 src.chan = v->gpr.chan();
335 update_ngpr(src.sel);
336 break;
337 case VLK_UNDEF:
338 case VLK_CONST: {
339 literal lv = v->literal_value;
340 src.chan = 0;
341
342 if (lv == literal(0))
343 src.sel = ALU_SRC_0;
344 else if (lv == literal(0.5f))
345 src.sel = ALU_SRC_0_5;
346 else if (lv == literal(1.0f))
347 src.sel = ALU_SRC_1;
348 else if (lv == literal(1))
349 src.sel = ALU_SRC_1_INT;
350 else if (lv == literal(-1))
351 src.sel = ALU_SRC_M_1_INT;
352 else {
353 src.sel = ALU_SRC_LITERAL;
354 src.chan = g->literal_chan(lv);
355 src.value = lv;
356 }
357 break;
358 }
359 case VLK_KCACHE: {
360 cf_node *clause = static_cast<cf_node*>(g->parent);
361 assert(clause->is_alu_clause());
362 sel_chan k = translate_kcache(clause, v);
363
364 assert(k && "kcache translation failed");
365
366 src.sel = k.sel();
367 src.chan = k.chan();
368 break;
369 }
370 case VLK_PARAM:
371 case VLK_SPECIAL_CONST:
372 src.sel = v->select.sel();
373 src.chan = v->select.chan();
374 break;
375 default:
376 assert(!"unknown value kind");
377 break;
378 }
379 }
380
381 while (si < 3) {
382 a->bc.src[si++].sel = 0;
383 }
384 }
385
386 void bc_finalizer::emit_set_grad(fetch_node* f) {
387
388 assert(f->src.size() == 12);
389 unsigned ops[2] = { FETCH_OP_SET_GRADIENTS_V, FETCH_OP_SET_GRADIENTS_H };
390
391 unsigned arg_start = 0;
392
393 for (unsigned op = 0; op < 2; ++op) {
394 fetch_node *n = sh.create_fetch();
395 n->bc.set_op(ops[op]);
396
397 // FIXME extract this loop into a separate method and reuse it
398
399 int reg = -1;
400
401 arg_start += 4;
402
403 for (unsigned chan = 0; chan < 4; ++chan) {
404
405 n->bc.dst_sel[chan] = SEL_MASK;
406
407 unsigned sel = SEL_MASK;
408
409 value *v = f->src[arg_start + chan];
410
411 if (!v || v->is_undef()) {
412 sel = SEL_MASK;
413 } else if (v->is_const()) {
414 literal l = v->literal_value;
415 if (l == literal(0))
416 sel = SEL_0;
417 else if (l == literal(1.0f))
418 sel = SEL_1;
419 else {
420 cerr << "invalid fetch constant operand " << chan << " ";
421 dump::dump_op(f);
422 cerr << "\n";
423 abort();
424 }
425
426 } else if (v->is_any_gpr()) {
427 unsigned vreg = v->gpr.sel();
428 unsigned vchan = v->gpr.chan();
429
430 if (reg == -1)
431 reg = vreg;
432 else if ((unsigned)reg != vreg) {
433 cerr << "invalid fetch source operand " << chan << " ";
434 dump::dump_op(f);
435 cerr << "\n";
436 abort();
437 }
438
439 sel = vchan;
440
441 } else {
442 cerr << "invalid fetch source operand " << chan << " ";
443 dump::dump_op(f);
444 cerr << "\n";
445 abort();
446 }
447
448 n->bc.src_sel[chan] = sel;
449 }
450
451 if (reg >= 0)
452 update_ngpr(reg);
453
454 n->bc.src_gpr = reg >= 0 ? reg : 0;
455
456 f->insert_before(n);
457 }
458
459 }
460
461 void bc_finalizer::finalize_fetch(fetch_node* f) {
462
463 int reg = -1;
464
465 // src
466
467 unsigned src_count = 4;
468
469 unsigned flags = f->bc.op_ptr->flags;
470
471 if (flags & FF_VTX) {
472 src_count = 1;
473 } else if (flags & FF_USEGRAD) {
474 emit_set_grad(f);
475 }
476
477 for (unsigned chan = 0; chan < src_count; ++chan) {
478
479 unsigned sel = f->bc.src_sel[chan];
480
481 if (sel > SEL_W)
482 continue;
483
484 value *v = f->src[chan];
485
486 if (v->is_undef()) {
487 sel = SEL_MASK;
488 } else if (v->is_const()) {
489 literal l = v->literal_value;
490 if (l == literal(0))
491 sel = SEL_0;
492 else if (l == literal(1.0f))
493 sel = SEL_1;
494 else {
495 cerr << "invalid fetch constant operand " << chan << " ";
496 dump::dump_op(f);
497 cerr << "\n";
498 abort();
499 }
500
501 } else if (v->is_any_gpr()) {
502 unsigned vreg = v->gpr.sel();
503 unsigned vchan = v->gpr.chan();
504
505 if (reg == -1)
506 reg = vreg;
507 else if ((unsigned)reg != vreg) {
508 cerr << "invalid fetch source operand " << chan << " ";
509 dump::dump_op(f);
510 cerr << "\n";
511 abort();
512 }
513
514 sel = vchan;
515
516 } else {
517 cerr << "invalid fetch source operand " << chan << " ";
518 dump::dump_op(f);
519 cerr << "\n";
520 abort();
521 }
522
523 f->bc.src_sel[chan] = sel;
524 }
525
526 if (reg >= 0)
527 update_ngpr(reg);
528
529 f->bc.src_gpr = reg >= 0 ? reg : 0;
530
531 // dst
532
533 reg = -1;
534
535 unsigned dst_swz[4] = {SEL_MASK, SEL_MASK, SEL_MASK, SEL_MASK};
536
537 for (unsigned chan = 0; chan < 4; ++chan) {
538
539 unsigned sel = f->bc.dst_sel[chan];
540
541 if (sel == SEL_MASK)
542 continue;
543
544 value *v = f->dst[chan];
545 if (!v)
546 continue;
547
548 if (v->is_any_gpr()) {
549 unsigned vreg = v->gpr.sel();
550 unsigned vchan = v->gpr.chan();
551
552 if (reg == -1)
553 reg = vreg;
554 else if ((unsigned)reg != vreg) {
555 cerr << "invalid fetch dst operand " << chan << " ";
556 dump::dump_op(f);
557 cerr << "\n";
558 abort();
559 }
560
561 dst_swz[vchan] = sel;
562
563 } else {
564 cerr << "invalid fetch dst operand " << chan << " ";
565 dump::dump_op(f);
566 cerr << "\n";
567 abort();
568 }
569
570 }
571
572 for (unsigned i = 0; i < 4; ++i)
573 f->bc.dst_sel[i] = dst_swz[i];
574
575 assert(reg >= 0);
576
577 if (reg >= 0)
578 update_ngpr(reg);
579
580 f->bc.dst_gpr = reg >= 0 ? reg : 0;
581 }
582
583 void bc_finalizer::finalize_cf(cf_node* c) {
584
585 unsigned flags = c->bc.op_ptr->flags;
586
587 if (flags & CF_CALL) {
588 update_nstack(c->get_parent_region(), ctx.is_cayman() ? 1 : 2);
589 }
590
591 c->bc.end_of_program = 0;
592 last_cf = c;
593
594 if (flags & CF_EXP) {
595 c->bc.set_op(CF_OP_EXPORT);
596 last_export[c->bc.type] = c;
597
598 int reg = -1;
599
600 for (unsigned chan = 0; chan < 4; ++chan) {
601
602 unsigned sel = c->bc.sel[chan];
603
604 if (sel > SEL_W)
605 continue;
606
607 value *v = c->src[chan];
608
609 if (v->is_undef()) {
610 sel = SEL_MASK;
611 } else if (v->is_const()) {
612 literal l = v->literal_value;
613 if (l == literal(0))
614 sel = SEL_0;
615 else if (l == literal(1.0f))
616 sel = SEL_1;
617 else {
618 cerr << "invalid export constant operand " << chan << " ";
619 dump::dump_op(c);
620 cerr << "\n";
621 abort();
622 }
623
624 } else if (v->is_any_gpr()) {
625 unsigned vreg = v->gpr.sel();
626 unsigned vchan = v->gpr.chan();
627
628 if (reg == -1)
629 reg = vreg;
630 else if ((unsigned)reg != vreg) {
631 cerr << "invalid export source operand " << chan << " ";
632 dump::dump_op(c);
633 cerr << "\n";
634 abort();
635 }
636
637 sel = vchan;
638
639 } else {
640 cerr << "invalid export source operand " << chan << " ";
641 dump::dump_op(c);
642 cerr << "\n";
643 abort();
644 }
645
646 c->bc.sel[chan] = sel;
647 }
648
649 if (reg >= 0)
650 update_ngpr(reg);
651
652 c->bc.rw_gpr = reg >= 0 ? reg : 0;
653
654 } else if (flags & CF_MEM) {
655
656 int reg = -1;
657 unsigned mask = 0;
658
659 for (unsigned chan = 0; chan < 4; ++chan) {
660 value *v = c->src[chan];
661 if (!v || v->is_undef())
662 continue;
663
664 if (!v->is_any_gpr() || v->gpr.chan() != chan) {
665 cerr << "invalid source operand " << chan << " ";
666 dump::dump_op(c);
667 cerr << "\n";
668 abort();
669 }
670 unsigned vreg = v->gpr.sel();
671 if (reg == -1)
672 reg = vreg;
673 else if ((unsigned)reg != vreg) {
674 cerr << "invalid source operand " << chan << " ";
675 dump::dump_op(c);
676 cerr << "\n";
677 abort();
678 }
679
680 mask |= (1 << chan);
681 }
682
683 assert(reg >= 0 && mask);
684
685 if (reg >= 0)
686 update_ngpr(reg);
687
688 c->bc.rw_gpr = reg >= 0 ? reg : 0;
689 c->bc.comp_mask = mask;
690
691 if ((flags & CF_RAT) && (c->bc.type & 1)) {
692
693 reg = -1;
694
695 for (unsigned chan = 0; chan < 4; ++chan) {
696 value *v = c->src[4 + chan];
697 if (!v || v->is_undef())
698 continue;
699
700 if (!v->is_any_gpr() || v->gpr.chan() != chan) {
701 cerr << "invalid source operand " << chan << " ";
702 dump::dump_op(c);
703 cerr << "\n";
704 abort();
705 }
706 unsigned vreg = v->gpr.sel();
707 if (reg == -1)
708 reg = vreg;
709 else if ((unsigned)reg != vreg) {
710 cerr << "invalid source operand " << chan << " ";
711 dump::dump_op(c);
712 cerr << "\n";
713 abort();
714 }
715 }
716
717 assert(reg >= 0);
718
719 if (reg >= 0)
720 update_ngpr(reg);
721
722 c->bc.index_gpr = reg >= 0 ? reg : 0;
723 }
724
725
726
727 } else {
728
729 #if 0
730 if ((flags & (CF_BRANCH | CF_LOOP)) && !sh.uses_gradients) {
731 c->bc.valid_pixel_mode = 1;
732 }
733 #endif
734
735 }
736 }
737
738 sel_chan bc_finalizer::translate_kcache(cf_node* alu, value* v) {
739 unsigned sel = v->select.sel();
740 unsigned bank = sel >> 12;
741 unsigned chan = v->select.chan();
742 static const unsigned kc_base[] = {128, 160, 256, 288};
743
744 sel &= 4095;
745
746 unsigned line = sel >> 4;
747
748 for (unsigned k = 0; k < 4; ++k) {
749 bc_kcache &kc = alu->bc.kc[k];
750
751 if (kc.mode == KC_LOCK_NONE)
752 break;
753
754 if (kc.bank == bank && (kc.addr == line ||
755 (kc.mode == KC_LOCK_2 && kc.addr + 1 == line))) {
756
757 sel = kc_base[k] + (sel - (kc.addr << 4));
758
759 return sel_chan(sel, chan);
760 }
761 }
762
763 assert(!"kcache translation error");
764 return 0;
765 }
766
767 void bc_finalizer::update_ngpr(unsigned gpr) {
768 if (gpr < MAX_GPR - ctx.alu_temp_gprs && gpr >= ngpr)
769 ngpr = gpr + 1;
770 }
771
772 void bc_finalizer::update_nstack(region_node* r, unsigned add) {
773 unsigned loops = 0;
774 unsigned ifs = 0;
775
776 while (r) {
777 if (r->is_loop())
778 ++loops;
779 else
780 ++ifs;
781
782 r = r->get_parent_region();
783 }
784
785 unsigned stack_elements = (loops * ctx.stack_entry_size) + ifs + add;
786
787 // FIXME calculate more precisely
788 if (ctx.is_evergreen()) {
789 ++stack_elements;
790 } else {
791 stack_elements += 2;
792 if (ctx.is_cayman())
793 ++stack_elements;
794 }
795
796 unsigned stack_entries = (stack_elements + 3) >> 2;
797
798 if (nstack < stack_entries)
799 nstack = stack_entries;
800 }
801
802 void bc_finalizer::cf_peephole() {
803
804 for (node_iterator N, I = sh.root->begin(), E = sh.root->end(); I != E;
805 I = N) {
806 N = I; ++N;
807
808 cf_node *c = static_cast<cf_node*>(*I);
809
810 if (c->jump_after_target) {
811 c->jump_target = static_cast<cf_node*>(c->jump_target->next);
812 c->jump_after_target = false;
813 }
814
815 if (c->is_cf_op(CF_OP_POP)) {
816 node *p = c->prev;
817 if (p->is_alu_clause()) {
818 cf_node *a = static_cast<cf_node*>(p);
819
820 if (a->bc.op == CF_OP_ALU) {
821 a->bc.set_op(CF_OP_ALU_POP_AFTER);
822 c->remove();
823 }
824 }
825 } else if (c->is_cf_op(CF_OP_JUMP) && c->jump_target == c->next) {
826 // if JUMP is immediately followed by its jump target,
827 // then JUMP is useless and we can eliminate it
828 c->remove();
829 }
830 }
831 }
832
833 } // namespace r600_sb