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 RA_DEBUG 0
28
29#if RA_DEBUG
30#define RA_DUMP(q) do { q } while (0)
31#else
32#define RA_DUMP(q)
33#endif
34
35#include <cstring>
36
37#include "sb_bc.h"
38#include "sb_shader.h"
39#include "sb_pass.h"
40
41namespace r600_sb {
42
43class regbits {
44	typedef uint32_t basetype;
45	static const unsigned bt_bytes = sizeof(basetype);
46	static const unsigned bt_index_shift = 5;
47	static const unsigned bt_index_mask = (1u << bt_index_shift) - 1;
48	static const unsigned bt_bits = bt_bytes << 3;
49	static const unsigned size = MAX_GPR * 4 / bt_bits;
50
51	basetype dta[size];
52
53	unsigned num_temps;
54
55public:
56
57	regbits(unsigned num_temps) : dta(), num_temps(num_temps) {}
58	regbits(unsigned num_temps, unsigned value)	: num_temps(num_temps)
59	{ set_all(value); }
60
61	regbits(shader &sh, val_set &vs) : num_temps(sh.get_ctx().alu_temp_gprs)
62	{ set_all(1); from_val_set(sh, vs); }
63
64	void set_all(unsigned val);
65	void from_val_set(shader &sh, val_set &vs);
66
67	void set(unsigned index);
68	void clear(unsigned index);
69	bool get(unsigned index);
70
71	void set(unsigned index, unsigned val);
72
73	sel_chan find_free_bit();
74	sel_chan find_free_chans(unsigned mask);
75	sel_chan find_free_chan_by_mask(unsigned mask);
76	sel_chan find_free_array(unsigned size, unsigned mask);
77
78	void dump();
79};
80
81// =======================================
82
83void regbits::dump() {
84	for (unsigned i = 0; i < size * bt_bits; ++i) {
85
86		if (!(i & 31))
87			sblog << "\n";
88
89		if (!(i & 3)) {
90			sblog.print_w(i / 4, 7);
91			sblog << " ";
92		}
93
94		sblog << (get(i) ? 1 : 0);
95	}
96}
97
98
99void regbits::set_all(unsigned v) {
100	memset(&dta, v ? 0xFF : 0x00, size * bt_bytes);
101}
102
103void regbits::from_val_set(shader &sh, val_set& vs) {
104	val_set &s = vs;
105	unsigned g;
106	for (val_set::iterator I = s.begin(sh), E = s.end(sh); I != E; ++I) {
107		value *v = *I;
108		if (v->is_any_gpr()) {
109			g = v->get_final_gpr();
110			if (!g)
111				continue;
112		} else
113			continue;
114
115		assert(g);
116		--g;
117		assert(g < 512);
118		clear(g);
119	}
120}
121
122void regbits::set(unsigned index) {
123	unsigned ih = index >> bt_index_shift;
124	unsigned il = index & bt_index_mask;
125	dta[ih] |= ((basetype)1u << il);
126}
127
128void regbits::clear(unsigned index) {
129	unsigned ih = index >> bt_index_shift;
130	unsigned il = index & bt_index_mask;
131	assert(ih < size);
132	dta[ih] &= ~((basetype)1u << il);
133}
134
135bool regbits::get(unsigned index) {
136	unsigned ih = index >> bt_index_shift;
137	unsigned il = index & bt_index_mask;
138	return dta[ih] & ((basetype)1u << il);
139}
140
141void regbits::set(unsigned index, unsigned val) {
142	unsigned ih = index >> bt_index_shift;
143	unsigned il = index & bt_index_mask;
144	basetype bm = 1u << il;
145	dta[ih] = (dta[ih] & ~bm) | (val << il);
146}
147
148// free register for ra means the bit is set
149sel_chan regbits::find_free_bit() {
150	unsigned elt = 0;
151	unsigned bit = 0;
152
153	while (elt < size && !dta[elt])
154		++elt;
155
156	if (elt >= size)
157		return 0;
158
159	bit = __builtin_ctz(dta[elt]) + (elt << bt_index_shift);
160
161	assert(bit < ((MAX_GPR - num_temps) << 2));
162
163	return bit + 1;
164}
165
166// find free gpr component to use as indirectly addressable array
167sel_chan regbits::find_free_array(unsigned length, unsigned mask) {
168	unsigned cc[4] = {};
169
170	// FIXME optimize this. though hopefully we won't have a lot of arrays
171	for (unsigned a = 0; a < MAX_GPR - num_temps; ++a) {
172		for(unsigned c = 0; c < MAX_CHAN; ++c) {
173			if (mask & (1 << c)) {
174				if (get((a << 2) | c)) {
175					if (++cc[c] == length)
176						return sel_chan(a - length + 1, c);
177				} else {
178					cc[c] = 0;
179				}
180			}
181		}
182	}
183	return 0;
184}
185
186sel_chan regbits::find_free_chans(unsigned mask) {
187	unsigned elt = 0;
188	unsigned bit = 0;
189
190	assert (!(mask & ~0xF));
191	basetype cd = dta[elt];
192
193	do {
194		if (!cd) {
195			if (++elt < size) {
196				cd = dta[elt];
197				bit = 0;
198				continue;
199			} else
200				return 0;
201		}
202
203		unsigned p = __builtin_ctz(cd) & ~(basetype)3u;
204
205		assert (p <= bt_bits - bit);
206		bit += p;
207		cd >>= p;
208
209		if ((cd & mask) == mask) {
210			return ((elt << bt_index_shift) | bit) + 1;
211		}
212
213		bit += 4;
214		cd >>= 4;
215
216	} while (1);
217
218	return 0;
219}
220
221sel_chan regbits::find_free_chan_by_mask(unsigned mask) {
222	unsigned elt = 0;
223	unsigned bit = 0;
224
225	assert (!(mask & ~0xF));
226	basetype cd = dta[elt];
227
228	do {
229		if (!cd) {
230			if (++elt < size) {
231				cd = dta[elt];
232				bit = 0;
233				continue;
234			} else
235				return 0;
236		}
237
238		unsigned p = __builtin_ctz(cd) & ~(basetype)3u;
239
240		assert (p <= bt_bits - bit);
241		bit += p;
242		cd >>= p;
243
244		if (cd & mask) {
245			unsigned nb = __builtin_ctz(cd & mask);
246			unsigned ofs = ((elt << bt_index_shift) | bit);
247			return nb + ofs + 1;
248		}
249
250		bit += 4;
251		cd >>= 4;
252
253	} while (1);
254
255	return 0;
256}
257
258// ================================
259
260void ra_init::alloc_arrays() {
261
262	gpr_array_vec &ga = sh.arrays();
263
264	for(gpr_array_vec::iterator I = ga.begin(), E = ga.end(); I != E; ++I) {
265		gpr_array *a = *I;
266
267		RA_DUMP(
268			sblog << "array [" << a->array_size << "] at " << a->base_gpr << "\n";
269			sblog << "\n";
270		);
271
272		// skip preallocated arrays (e.g. with preloaded inputs)
273		if (a->gpr) {
274			RA_DUMP( sblog << "   FIXED at " << a->gpr << "\n"; );
275			continue;
276		}
277
278		bool dead = a->is_dead();
279
280		if (dead) {
281			RA_DUMP( sblog << "   DEAD\n"; );
282			continue;
283		}
284
285		val_set &s = a->interferences;
286
287
288		for (val_set::iterator I = s.begin(sh), E = s.end(sh); I != E; ++I) {
289			value *v = *I;
290			if (v->array == a)
291				s.remove_val(v);
292		}
293
294		RA_DUMP(
295			sblog << "  interf: ";
296			dump::dump_set(sh, s);
297			sblog << "\n";
298		);
299
300		regbits rb(sh, s);
301
302		sel_chan base = rb.find_free_array(a->array_size,
303		                                   (1 << a->base_gpr.chan()));
304
305		RA_DUMP( sblog << "  found base: " << base << "\n"; );
306
307		a->gpr = base;
308	}
309}
310
311
312int ra_init::run() {
313
314	alloc_arrays();
315
316	return ra_node(sh.root) ? 0 : 1;
317}
318
319bool ra_init::ra_node(container_node* c) {
320
321	for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
322		node *n = *I;
323		if (n->type == NT_OP) {
324			if (!process_op(n))
325                           return false;
326		}
327		if (n->is_container() && !n->is_alu_packed()) {
328			if (!ra_node(static_cast<container_node*>(n)))
329                           return false;
330		}
331	}
332        return true;
333}
334
335bool ra_init::process_op(node* n) {
336
337	bool copy = n->is_copy_mov();
338
339	RA_DUMP(
340		sblog << "ra_init: process_op : ";
341		dump::dump_op(n);
342		sblog << "\n";
343	);
344
345	if (n->is_alu_packed()) {
346		for (vvec::iterator I = n->src.begin(), E = n->src.end(); I != E; ++I) {
347			value *v = *I;
348			if (v && v->is_sgpr() && v->constraint &&
349					v->constraint->kind == CK_PACKED_BS) {
350				color_bs_constraint(v->constraint);
351				break;
352			}
353		}
354	}
355
356	if (n->is_fetch_inst() || n->is_cf_inst()) {
357		for (vvec::iterator I = n->src.begin(), E = n->src.end(); I != E; ++I) {
358			value *v = *I;
359			if (v && v->is_sgpr())
360				if (!color(v))
361                                       return false;
362		}
363	}
364
365	for (vvec::iterator I = n->dst.begin(), E = n->dst.end(); I != E; ++I) {
366		value *v = *I;
367		if (!v)
368			continue;
369		if (v->is_sgpr()) {
370			if (!v->gpr) {
371				if (copy && !v->constraint) {
372					value *s = *(n->src.begin() + (I - n->dst.begin()));
373					assert(s);
374					if (s->is_sgpr()) {
375						assign_color(v, s->gpr);
376					}
377				} else
378                                   if (!color(v))
379                                          return false;
380			}
381		}
382	}
383        return true;
384}
385
386void ra_init::color_bs_constraint(ra_constraint* c) {
387	vvec &vv = c->values;
388	assert(vv.size() <= 8);
389
390	RA_DUMP(
391		sblog << "color_bs_constraint: ";
392		dump::dump_vec(vv);
393		sblog << "\n";
394	);
395
396	regbits rb(ctx.alu_temp_gprs);
397
398	unsigned chan_count[4] = {};
399	unsigned allowed_chans = 0x0F;
400
401	for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
402		value *v = *I;
403
404		if (!v || v->is_dead())
405			continue;
406
407		sel_chan gpr = v->get_final_gpr();
408
409		val_set interf;
410
411		if (v->chunk)
412			sh.coal.get_chunk_interferences(v->chunk, interf);
413		else
414			interf = v->interferences;
415
416		RA_DUMP(
417			sblog << "   processing " << *v << "  interferences : ";
418			dump::dump_set(sh, interf);
419			sblog << "\n";
420		);
421
422		if (gpr) {
423			unsigned chan = gpr.chan();
424			if (chan_count[chan] < 3) {
425				++chan_count[chan];
426				continue;
427			} else {
428				v->flags &= ~VLF_FIXED;
429				allowed_chans &= ~(1 << chan);
430				assert(allowed_chans);
431			}
432		}
433
434		v->gpr = 0;
435
436		gpr = 1;
437		rb.set_all(1);
438
439
440		rb.from_val_set(sh, interf);
441
442		RA_DUMP(
443			sblog << "   regbits : ";
444			rb.dump();
445			sblog << "\n";
446		);
447
448		while (allowed_chans && gpr.sel() < sh.num_nontemp_gpr()) {
449
450			while (rb.get(gpr - 1) == 0)
451				gpr = gpr + 1;
452
453			RA_DUMP(
454				sblog << "    trying " << gpr << "\n";
455			);
456
457			unsigned chan = gpr.chan();
458			if (chan_count[chan] < 3) {
459				++chan_count[chan];
460
461				if (v->chunk) {
462					vvec::iterator F = std::find(v->chunk->values.begin(),
463					                             v->chunk->values.end(),
464					                             v);
465					v->chunk->values.erase(F);
466					v->chunk = NULL;
467				}
468
469				assign_color(v, gpr);
470				break;
471			} else {
472				allowed_chans &= ~(1 << chan);
473			}
474			gpr = gpr + 1;
475		}
476
477		if (!gpr) {
478			sblog << "color_bs_constraint: failed...\n";
479			assert(!"coloring failed");
480		}
481	}
482}
483
484bool ra_init::color(value* v) {
485
486	if (v->constraint && v->constraint->kind == CK_PACKED_BS) {
487		color_bs_constraint(v->constraint);
488		return true;
489	}
490
491	if (v->chunk && v->chunk->is_fixed())
492		return true;
493
494	RA_DUMP(
495		sblog << "coloring ";
496		dump::dump_val(v);
497		sblog << "   interferences ";
498		dump::dump_set(sh, v->interferences);
499		sblog << "\n";
500	);
501
502	if (v->is_reg_pinned()) {
503		assert(v->is_chan_pinned());
504		assign_color(v, v->pin_gpr);
505		return true;
506	}
507
508	regbits rb(sh, v->interferences);
509	sel_chan c;
510
511	if (v->is_chan_pinned()) {
512		unsigned mask = 1 << v->pin_gpr.chan();
513		c = rb.find_free_chans(mask) + v->pin_gpr.chan();
514	} else {
515		unsigned cm = get_preferable_chan_mask();
516		c = rb.find_free_chan_by_mask(cm);
517	}
518
519        if (!c || c.sel() >= 128 - ctx.alu_temp_gprs)
520           return false;
521	assign_color(v, c);
522        return true;
523}
524
525void ra_init::assign_color(value* v, sel_chan c) {
526	add_prev_chan(c.chan());
527	v->gpr = c;
528	RA_DUMP(
529		sblog << "colored ";
530		dump::dump_val(v);
531		sblog << " to " << c << "\n";
532	);
533}
534
535// ===================================================
536
537int ra_split::run() {
538	split(sh.root);
539	return 0;
540}
541
542void ra_split::split_phi_src(container_node *loc, container_node *c,
543                             unsigned id, bool loop) {
544	for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
545		node *p = *I;
546		value* &v = p->src[id], *d = p->dst[0];
547		assert(v);
548
549		if (!d->is_sgpr() || v->is_undef())
550			continue;
551
552		value *t = sh.create_temp_value();
553		alu_node* n = sh.create_copy_mov(t, v);
554		if (loop)
555			n->flags |= NF_DONT_MOVE;
556		if (loop && id == 0)
557			loc->insert_before(n);
558		else
559			loc->push_back(n);
560		v = t;
561
562		sh.coal.add_edge(v, d, coalescer::phi_cost);
563	}
564}
565
566void ra_split::split_phi_dst(node* loc, container_node *c, bool loop) {
567	for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
568		node *p = *I;
569		value* &v = p->dst[0];
570		assert(v);
571
572		if (!v->is_sgpr())
573			continue;
574
575		value *t = sh.create_temp_value();
576		node *cp = sh.create_copy_mov(v, t);
577		if (loop) {
578			cp->flags |= NF_DONT_MOVE;
579			static_cast<container_node*>(loc)->push_front(cp);
580		} else
581			loc->insert_after(cp);
582		v = t;
583	}
584}
585
586
587void ra_split::init_phi_constraints(container_node *c) {
588	for (node_iterator I = c->begin(), E = c->end(); I != E; ++I) {
589		node *p = *I;
590		ra_constraint *cc = sh.coal.create_constraint(CK_PHI);
591		cc->values.push_back(p->dst[0]);
592
593		for (vvec::iterator I = p->src.begin(), E = p->src.end(); I != E; ++I) {
594			value *v = *I;
595			if (v->is_sgpr())
596				cc->values.push_back(v);
597		}
598
599		cc->update_values();
600	}
601}
602
603void ra_split::split(container_node* n) {
604
605	if (n->type == NT_DEPART) {
606		depart_node *d = static_cast<depart_node*>(n);
607		if (d->target->phi)
608			split_phi_src(d, d->target->phi, d->dep_id, false);
609	} else if (n->type == NT_REPEAT) {
610		repeat_node *r = static_cast<repeat_node*>(n);
611		if (r->target->loop_phi)
612			split_phi_src(r, r->target->loop_phi, r->rep_id, true);
613	} else if (n->type == NT_REGION) {
614		region_node *r = static_cast<region_node*>(n);
615		if (r->phi) {
616			split_phi_dst(r, r->phi, false);
617		}
618		if (r->loop_phi) {
619			split_phi_dst(r->get_entry_code_location(), r->loop_phi,
620					true);
621			split_phi_src(r, r->loop_phi, 0, true);
622		}
623	}
624
625	for (node_riterator N, I = n->rbegin(), E = n->rend(); I != E; I = N) {
626		N = I;
627		++N;
628		node *o = *I;
629		if (o->type == NT_OP) {
630			split_op(o);
631		} else if (o->is_container()) {
632			split(static_cast<container_node*>(o));
633		}
634	}
635
636	if (n->type == NT_REGION) {
637		region_node *r = static_cast<region_node*>(n);
638		if (r->phi)
639			init_phi_constraints(r->phi);
640		if (r->loop_phi)
641			init_phi_constraints(r->loop_phi);
642	}
643}
644
645void ra_split::split_op(node* n) {
646	switch(n->subtype) {
647		case NST_ALU_PACKED_INST:
648			split_alu_packed(static_cast<alu_packed_node*>(n));
649			break;
650		case NST_FETCH_INST:
651		case NST_CF_INST:
652			split_vector_inst(n);
653		default:
654			break;
655	}
656}
657
658void ra_split::split_packed_ins(alu_packed_node *n) {
659	vvec vv = n->src;
660	vvec sv, dv;
661
662	for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
663
664		value *&v = *I;
665
666		if (v && v->is_any_gpr() && !v->is_undef()) {
667
668			vvec::iterator F = std::find(sv.begin(), sv.end(), v);
669			value *t;
670
671			if (F != sv.end()) {
672				t = *(dv.begin() + (F - sv.begin()));
673			} else {
674				t = sh.create_temp_value();
675				sv.push_back(v);
676				dv.push_back(t);
677			}
678			v = t;
679		}
680	}
681
682	unsigned cnt = sv.size();
683
684	if (cnt > 0) {
685		n->src = vv;
686		for (vvec::iterator SI = sv.begin(), DI = dv.begin(), SE = sv.end();
687				SI != SE; ++SI, ++DI) {
688			n->insert_before(sh.create_copy_mov(*DI, *SI));
689		}
690
691		ra_constraint *c = sh.coal.create_constraint(CK_PACKED_BS);
692		c->values = dv;
693		c->update_values();
694	}
695}
696
697// TODO handle other packed ops for cayman
698void ra_split::split_alu_packed(alu_packed_node* n) {
699	switch (n->op()) {
700		case ALU_OP2_DOT4:
701		case ALU_OP2_DOT4_IEEE:
702		case ALU_OP2_CUBE:
703			split_packed_ins(n);
704			break;
705		default:
706			break;
707	}
708}
709
710void ra_split::split_vec(vvec &vv, vvec &v1, vvec &v2, bool allow_swz) {
711	unsigned ch = 0;
712	for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I, ++ch) {
713
714		value* &o = *I;
715
716		if (o) {
717
718			assert(!o->is_dead());
719
720			if (o->is_undef() || o->is_geometry_emit() || o->is_scratch())
721				continue;
722
723			if (allow_swz && o->is_float_0_or_1())
724				continue;
725
726			value *t;
727			vvec::iterator F =
728					allow_swz ? std::find(v2.begin(), v2.end(), o) : v2.end();
729
730			if (F != v2.end()) {
731				t = *(v1.begin() + (F - v2.begin()));
732			} else {
733				t = sh.create_temp_value();
734
735				if (!allow_swz) {
736					t->flags |= VLF_PIN_CHAN;
737					t->pin_gpr = sel_chan(0, ch);
738				}
739
740				v2.push_back(o);
741				v1.push_back(t);
742			}
743			o = t;
744		}
745	}
746}
747
748void ra_split::split_vector_inst(node* n) {
749	ra_constraint *c;
750
751	bool call_fs = n->is_cf_op(CF_OP_CALL_FS);
752	bool no_src_swizzle = n->is_cf_inst() && (n->cf_op_flags() & CF_MEM);
753
754	no_src_swizzle |= n->is_fetch_op(FETCH_OP_VFETCH) ||
755			n->is_fetch_op(FETCH_OP_SEMFETCH);
756
757	no_src_swizzle |= n->is_fetch_inst() && (n->fetch_op_flags() & FF_GDS);
758
759	if (!n->src.empty() && !call_fs) {
760
761		// we may have more than one source vector -
762		// fetch instructions with FF_USEGRAD have gradient values in
763		// src vectors 1 (src[4-7] and 2 (src[8-11])
764
765		unsigned nvec = n->src.size() >> 2;
766		assert(nvec << 2 <= n->src.size());
767
768		for (unsigned nv = 0; nv < nvec; ++nv) {
769			vvec sv, tv, nsrc(4);
770			unsigned arg_start = nv << 2;
771
772			std::copy(n->src.begin() + arg_start,
773			          n->src.begin() + arg_start + 4,
774			          nsrc.begin());
775
776			split_vec(nsrc, tv, sv, !no_src_swizzle);
777
778			unsigned cnt = sv.size();
779
780			if (no_src_swizzle || cnt) {
781
782				std::copy(nsrc.begin(), nsrc.end(), n->src.begin() + arg_start);
783
784				for(unsigned i = 0, s = tv.size(); i < s; ++i) {
785					n->insert_before(sh.create_copy_mov(tv[i], sv[i]));
786				}
787
788				c = sh.coal.create_constraint(CK_SAME_REG);
789				c->values = tv;
790				c->update_values();
791			}
792		}
793	}
794
795	if (!n->dst.empty()) {
796		vvec sv, tv, ndst = n->dst;
797
798		split_vec(ndst, tv, sv, true);
799
800		if (sv.size()) {
801			n->dst = ndst;
802
803			node *lp = n;
804			for(unsigned i = 0, s = tv.size(); i < s; ++i) {
805				lp->insert_after(sh.create_copy_mov(sv[i], tv[i]));
806				lp = lp->next;
807			}
808
809			if (call_fs) {
810				for (unsigned i = 0, cnt = tv.size(); i < cnt; ++i) {
811					value *v = tv[i];
812					value *s = sv[i];
813					if (!v)
814						continue;
815
816					v->flags |= VLF_PIN_REG | VLF_PIN_CHAN;
817					s->flags &= ~(VLF_PIN_REG | VLF_PIN_CHAN);
818					sel_chan sel;
819
820					if (s->is_rel()) {
821						assert(s->rel->is_const());
822						sel = sel_chan(s->select.sel() +
823										 s->rel->get_const_value().u,
824						             s->select.chan());
825					} else
826						sel = s->select;
827
828					v->gpr = v->pin_gpr = sel;
829					v->fix();
830				}
831			} else {
832				c = sh.coal.create_constraint(CK_SAME_REG);
833				c->values = tv;
834				c->update_values();
835			}
836		}
837	}
838}
839
840void ra_init::add_prev_chan(unsigned chan) {
841	prev_chans = (prev_chans << 4) | (1 << chan);
842}
843
844unsigned ra_init::get_preferable_chan_mask() {
845	unsigned i, used_chans = 0;
846	unsigned chans = prev_chans;
847
848	for (i = 0; i < ra_tune; ++i) {
849		used_chans |= chans;
850		chans >>= 4;
851	}
852
853	return (~used_chans) & 0xF;
854}
855
856} // namespace r600_sb
857