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 #include "sb_bc.h"
28 #include "sb_shader.h"
29 #include "sb_pass.h"
30 
31 namespace r600_sb {
32 
accept(vpass & p,bool enter)33 bool node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)34 bool container_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)35 bool alu_group_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)36 bool alu_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)37 bool cf_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)38 bool fetch_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)39 bool region_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
40 
accept(vpass & p,bool enter)41 bool repeat_node::accept(vpass& p, bool enter) {
42 	return p.visit(*this, enter);
43 }
44 
accept(vpass & p,bool enter)45 bool depart_node::accept(vpass& p, bool enter) {
46 	return p.visit(*this, enter);
47 }
accept(vpass & p,bool enter)48 bool if_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)49 bool bb_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
accept(vpass & p,bool enter)50 bool alu_packed_node::accept(vpass& p, bool enter) {
51 	return p.visit(*this, enter);
52 }
53 
init_args(bool repl)54 void alu_packed_node::init_args(bool repl) {
55 	alu_node *p = static_cast<alu_node*>(first);
56 	assert(p->is_valid());
57 	while (p) {
58 		dst.insert(dst.end(), p->dst.begin(), p->dst.end());
59 		src.insert(src.end(), p->src.begin(), p->src.end());
60 		p = static_cast<alu_node*>(p->next);
61 	}
62 
63 	value *replicated_value = NULL;
64 
65 	for (vvec::iterator I = dst.begin(), E = dst.end(); I != E; ++I) {
66 		value *v = *I;
67 		if (v) {
68 			if (repl) {
69 				if (replicated_value)
70 					v->assign_source(replicated_value);
71 				else
72 					replicated_value = v;
73 			}
74 
75 			v->def = this;
76 		}
77 	}
78 }
79 
insert_node_before(node * s,node * n)80 void container_node::insert_node_before(node* s, node* n) {
81 	if (s->prev) {
82 		node *sp = s->prev;
83 		sp->next = n;
84 		n->prev = sp;
85 		n->next = s;
86 		s->prev = n;
87 	} else {
88 		n->next = s;
89 		s->prev = n;
90 		first = n;
91 	}
92 	n->parent = this;
93 }
94 
insert_node_after(node * s,node * n)95 void container_node::insert_node_after(node* s, node* n) {
96 	if (s->next) {
97 		node *sn = s->next;
98 		sn->prev = n;
99 		n->next = sn;
100 		n->prev = s;
101 		s->next = n;
102 	} else {
103 		n->prev = s;
104 		s->next = n;
105 		last = n;
106 	}
107 	n->parent = this;
108 }
109 
move(iterator b,iterator e)110 void container_node::move(iterator b, iterator e) {
111 	assert(b != e);
112 
113 	container_node *source_container = b->parent;
114 	node *l = source_container->cut(b, e);
115 
116 	first = last = l;
117 	first->parent = this;
118 
119 	while (last->next) {
120 		last = last->next;
121 		last->parent = this;
122 	}
123 }
124 
cut(iterator b,iterator e)125 node* container_node::cut(iterator b, iterator e) {
126 	assert(!*b || b->parent == this);
127 	assert(!*e || e->parent == this);
128 	assert(b != e);
129 
130 	if (b->prev) {
131 		b->prev->next = *e;
132 	} else {
133 		first = *e;
134 	}
135 
136 	if (*e) {
137 		e->prev->next = NULL;
138 		e->prev = b->prev;
139 	} else {
140 		last->next = NULL;
141 		last = b->prev;
142 	}
143 
144 	b->prev = NULL;
145 
146 	return *b;
147 }
148 
count()149 unsigned container_node::count() {
150 	unsigned c = 0;
151 	node *t = first;
152 	while (t) {
153 		t = t->next;
154 		c++;
155 	}
156 	return c;
157 }
158 
remove_node(node * n)159 void container_node::remove_node(node *n) {
160 	if (n->prev)
161 		n->prev->next = n->next;
162 	else
163 		first = n->next;
164 	if (n->next)
165 		n->next->prev = n->prev;
166 	else
167 		last = n->prev;
168 	n->parent = NULL;
169 }
170 
expand(container_node * n)171 void container_node::expand(container_node *n) {
172 	if (!n->empty()) {
173 		node *e0 = n->first;
174 		node *e1 = n->last;
175 
176 		e0->prev = n->prev;
177 		if (e0->prev) {
178 			e0->prev->next = e0;
179 		} else {
180 			first = e0;
181 		}
182 
183 		e1->next = n->next;
184 		if (e1->next)
185 			e1->next->prev = e1;
186 		else
187 			last = e1;
188 
189 		do {
190 			e0->parent = this;
191 			e0 = e0->next;
192 		} while (e0 != e1->next);
193 	} else
194 		remove_node(n);
195 }
196 
push_back(node * n)197 void container_node::push_back(node *n) {
198 	if (last) {
199 		last->next = n;
200 		n->next = NULL;
201 		n->prev = last;
202 		last = n;
203 	} else {
204 		assert(!first);
205 		first = last = n;
206 		n->prev = n->next = NULL;
207 	}
208 	n->parent = this;
209 }
push_front(node * n)210 void container_node::push_front(node *n) {
211 	if (first) {
212 		first->prev = n;
213 		n->prev = NULL;
214 		n->next = first;
215 		first = n;
216 	} else {
217 		assert(!last);
218 		first = last = n;
219 		n->prev = n->next = NULL;
220 	}
221 	n->parent = this;
222 }
223 
insert_before(node * n)224 void node::insert_before(node* n) {
225 	 parent->insert_node_before(this, n);
226 }
227 
insert_after(node * n)228 void node::insert_after(node* n) {
229 	 parent->insert_node_after(this, n);
230 }
231 
replace_with(node * n)232 void node::replace_with(node* n) {
233 	n->prev = prev;
234 	n->next = next;
235 	n->parent = parent;
236 	if (prev)
237 		prev->next = n;
238 	if (next)
239 		next->prev = n;
240 
241 	if (parent->first == this)
242 		parent->first = n;
243 
244 	if (parent->last == this)
245 		parent->last = n;
246 
247 	parent = NULL;
248 	next = prev = NULL;
249 }
250 
expand()251 void container_node::expand() {
252 	 parent->expand(this);
253 }
254 
remove()255 void node::remove() {parent->remove_node(this);
256 }
257 
hash_src() const258 value_hash node::hash_src() const {
259 
260 	value_hash h = 12345;
261 
262 	for (int k = 0, e = src.size(); k < e; ++k) {
263 		value *s = src[k];
264 		if (s)
265 			h ^=  (s->hash());
266 	}
267 
268 	return h;
269 }
270 
271 
hash() const272 value_hash node::hash() const {
273 
274 	if (parent && parent->subtype == NST_LOOP_PHI_CONTAINER)
275 		return 47451;
276 
277 	return hash_src() ^ (subtype << 13) ^ (type << 3);
278 }
279 
append_from(container_node * c)280 void r600_sb::container_node::append_from(container_node* c) {
281 	if (!c->first)
282 		return;
283 
284 	node *b = c->first;
285 
286 	if (last) {
287 		last->next = c->first;
288 		last->next->prev = last;
289 	} else {
290 		first = c->first;
291 	}
292 
293 	last = c->last;
294 	c->first = NULL;
295 	c->last = NULL;
296 
297 	while (b) {
298 		b->parent = this;
299 		b = b->next;
300 	}
301 }
302 
fold_dispatch(expr_handler * ex)303 bool node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
fold_dispatch(expr_handler * ex)304 bool container_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
fold_dispatch(expr_handler * ex)305 bool alu_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
fold_dispatch(expr_handler * ex)306 bool alu_packed_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
fold_dispatch(expr_handler * ex)307 bool fetch_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
fold_dispatch(expr_handler * ex)308 bool cf_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
309 
get_slot_mask()310 unsigned alu_packed_node::get_slot_mask() {
311 	unsigned mask = 0;
312 	for (node_iterator I = begin(), E = end(); I != E; ++I)
313 		mask |= 1 << static_cast<alu_node*>(*I)->bc.slot;
314 	return mask;
315 }
316 
update_packed_items(sb_context & ctx)317 void alu_packed_node::update_packed_items(sb_context &ctx) {
318 
319 	vvec::iterator SI(src.begin()), DI(dst.begin());
320 
321 	assert(first);
322 
323 	alu_node *c = static_cast<alu_node*>(first);
324 	unsigned flags = c->bc.op_ptr->flags;
325 	unsigned slot_flags = c->bc.slot_flags;
326 
327 	// fixup dst for instructions that replicate output
328 	if (((flags & AF_REPL) && slot_flags == AF_4V) ||
329 			(ctx.is_cayman() && slot_flags == AF_S)) {
330 
331 		value *swp[4] = {};
332 
333 		unsigned chan;
334 
335 		for (vvec::iterator I2 = dst.begin(), E2 = dst.end();
336 				I2 != E2; ++I2) {
337 			value *v = *I2;
338 			if (v) {
339 				chan = v->get_final_chan();
340 				assert(!swp[chan] || swp[chan] == v);
341 				swp[chan] = v;
342 			}
343 		}
344 
345 		chan = 0;
346 		for (vvec::iterator I2 = dst.begin(), E2 = dst.end();
347 				I2 != E2; ++I2, ++chan) {
348 			*I2 = swp[chan];
349 		}
350 	}
351 
352 	for (node_iterator I = begin(), E = end(); I != E; ++I) {
353 		alu_node *n = static_cast<alu_node*>(*I);
354 		assert(n);
355 
356 		for (vvec::iterator I2 = n->src.begin(), E2 = n->src.end();
357 				I2 != E2; ++I2, ++SI) {
358 			*I2 = *SI;
359 		}
360 		for (vvec::iterator I2 = n->dst.begin(), E2 = n->dst.end();
361 				I2 != E2; ++I2, ++DI) {
362 			*I2 = *DI;
363 		}
364 	}
365 }
366 
is_cf_op(unsigned op)367 bool node::is_cf_op(unsigned op) {
368 	if (!is_cf_inst())
369 		return false;
370 	cf_node *c = static_cast<cf_node*>(this);
371 	return c->bc.op == op;
372 }
373 
is_alu_op(unsigned op)374 bool node::is_alu_op(unsigned op) {
375 	if (!is_alu_inst())
376 		return false;
377 	alu_node *c = static_cast<alu_node*>(this);
378 	return c->bc.op == op;
379 }
380 
is_fetch_op(unsigned op)381 bool node::is_fetch_op(unsigned op) {
382 	if (!is_fetch_inst())
383 		return false;
384 	fetch_node *c = static_cast<fetch_node*>(this);
385 	return c->bc.op == op;
386 }
387 
388 
389 
is_mova()390 bool node::is_mova() {
391 	if (!is_alu_inst())
392 		return false;
393 	alu_node *a = static_cast<alu_node*>(this);
394 	return (a->bc.op_ptr->flags & AF_MOVA);
395 }
396 
is_pred_set()397 bool node::is_pred_set() {
398 	if (!is_alu_inst())
399 		return false;
400 	alu_node *a = static_cast<alu_node*>(this);
401 	return (a->bc.op_ptr->flags & AF_ANY_PRED);
402 }
403 
cf_op_flags()404 unsigned node::cf_op_flags() {
405 	assert(is_cf_inst());
406 	cf_node *c = static_cast<cf_node*>(this);
407 	return c->bc.op_ptr->flags;
408 }
409 
alu_op_flags()410 unsigned node::alu_op_flags() {
411 	assert(is_alu_inst());
412 	alu_node *c = static_cast<alu_node*>(this);
413 	return c->bc.op_ptr->flags;
414 }
415 
fetch_op_flags()416 unsigned node::fetch_op_flags() {
417 	assert(is_fetch_inst());
418 	fetch_node *c = static_cast<fetch_node*>(this);
419 	return c->bc.op_ptr->flags;
420 }
421 
alu_op_slot_flags()422 unsigned node::alu_op_slot_flags() {
423 	assert(is_alu_inst());
424 	alu_node *c = static_cast<alu_node*>(this);
425 	return c->bc.slot_flags;
426 }
427 
get_parent_region()428 region_node* node::get_parent_region() {
429 	node *p = this;
430 	while ((p = p->parent))
431 		if (p->is_region())
432 			return static_cast<region_node*>(p);
433 	return NULL;
434 }
435 
real_alu_count()436 unsigned container_node::real_alu_count() {
437 	unsigned c = 0;
438 	node *t = first;
439 	while (t) {
440 		if (t->is_alu_inst())
441 			++c;
442 		else if (t->is_alu_packed())
443 			c += static_cast<container_node*>(t)->count();
444 		t = t->next;
445 	}
446 	return c;
447 }
448 
collect_stats(node_stats & s)449 void container_node::collect_stats(node_stats& s) {
450 
451 	for (node_iterator I = begin(), E = end(); I != E; ++I) {
452 		node *n = *I;
453 		if (n->is_container()) {
454 			static_cast<container_node*>(n)->collect_stats(s);
455 		}
456 
457 		if (n->is_alu_inst()) {
458 			++s.alu_count;
459 			alu_node *a = static_cast<alu_node*>(n);
460 			if (a->bc.op_ptr->flags & AF_KILL)
461 				++s.alu_kill_count;
462 			else if (a->is_copy_mov())
463 				++s.alu_copy_mov_count;
464                        if (a->uses_ar())
465                           s.uses_ar = true;
466 		} else if (n->is_fetch_inst())
467 			++s.fetch_count;
468 		else if (n->is_cf_inst())
469 			++s.cf_count;
470 		else if (n->is_region()) {
471 			++s.region_count;
472 			region_node *r = static_cast<region_node*>(n);
473 			if(r->is_loop())
474 				++s.loop_count;
475 
476 			if (r->phi)
477 				s.phi_count += r->phi->count();
478 			if (r->loop_phi)
479 				s.loop_phi_count += r->loop_phi->count();
480 		}
481 		else if (n->is_depart())
482 			++s.depart_count;
483 		else if (n->is_repeat())
484 			++s.repeat_count;
485 		else if (n->is_if())
486 			++s.if_count;
487 	}
488 }
489 
expand_depart(depart_node * d)490 void region_node::expand_depart(depart_node *d) {
491 	depart_vec::iterator I = departs.begin() + d->dep_id, E;
492 	I = departs.erase(I);
493 	E = departs.end();
494 	while (I != E) {
495 		--(*I)->dep_id;
496 		++I;
497 	}
498 	d->expand();
499 }
500 
expand_repeat(repeat_node * r)501 void region_node::expand_repeat(repeat_node *r) {
502 	repeat_vec::iterator I = repeats.begin() + r->rep_id - 1, E;
503 	I = repeats.erase(I);
504 	E = repeats.end();
505 	while (I != E) {
506 		--(*I)->rep_id;
507 		++I;
508 	}
509 	r->expand();
510 }
511 
dump()512 void node_stats::dump() {
513 	sblog << "  alu_count : " << alu_count << "\n";
514 	sblog << "  alu_kill_count : " << alu_kill_count << "\n";
515 	sblog << "  alu_copy_mov_count : " << alu_copy_mov_count << "\n";
516 	sblog << "  cf_count : " << cf_count << "\n";
517 	sblog << "  fetch_count : " << fetch_count << "\n";
518 	sblog << "  region_count : " << region_count << "\n";
519 	sblog << "  loop_count : " << loop_count << "\n";
520 	sblog << "  phi_count : " << phi_count << "\n";
521 	sblog << "  loop_phi_count : " << loop_phi_count << "\n";
522 	sblog << "  depart_count : " << depart_count << "\n";
523 	sblog << "  repeat_count : " << repeat_count << "\n";
524 	sblog << "  if_count : " << if_count << "\n";
525 }
526 
interp_param()527 unsigned alu_node::interp_param() {
528 	if (!(bc.op_ptr->flags & AF_INTERP))
529 		return 0;
530 	unsigned param;
531 	if (bc.op_ptr->src_count == 2) {
532 		param = src[1]->select.sel();
533 	} else {
534 		param = src[0]->select.sel();
535 	}
536 	return param + 1;
537 }
538 
get_alu_group_node()539 alu_group_node* alu_node::get_alu_group_node() {
540 	node *p = parent;
541 	if (p) {
542 		if (p->subtype == NST_ALU_PACKED_INST) {
543 			assert(p->parent && p->parent->subtype == NST_ALU_GROUP);
544 			p = p->parent;
545 		}
546 		return static_cast<alu_group_node*>(p);
547 	}
548 	return NULL;
549 }
550 
551 } // namespace r600_sb
552