Home | History | Annotate | Download | only in sb
      1 /*
      2  * Copyright 2013 Vadim Girlin <vadimgirlin (at) 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 
     33 bool node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     34 bool container_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     35 bool alu_group_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     36 bool alu_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     37 bool cf_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     38 bool fetch_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     39 bool region_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     40 
     41 bool repeat_node::accept(vpass& p, bool enter) {
     42 	return p.visit(*this, enter);
     43 }
     44 
     45 bool depart_node::accept(vpass& p, bool enter) {
     46 	return p.visit(*this, enter);
     47 }
     48 bool if_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     49 bool bb_node::accept(vpass& p, bool enter) { return p.visit(*this, enter); }
     50 bool alu_packed_node::accept(vpass& p, bool enter) {
     51 	return p.visit(*this, enter);
     52 }
     53 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 }
    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 
    224 void node::insert_before(node* n) {
    225 	 parent->insert_node_before(this, n);
    226 }
    227 
    228 void node::insert_after(node* n) {
    229 	 parent->insert_node_after(this, n);
    230 }
    231 
    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 
    251 void container_node::expand() {
    252 	 parent->expand(this);
    253 }
    254 
    255 void node::remove() {parent->remove_node(this);
    256 }
    257 
    258 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 
    272 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 
    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 
    303 bool node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
    304 bool container_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
    305 bool alu_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
    306 bool alu_packed_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
    307 bool fetch_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
    308 bool cf_node::fold_dispatch(expr_handler* ex) { return ex->fold(*this); }
    309 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 		} else if (n->is_fetch_inst())
    465 			++s.fetch_count;
    466 		else if (n->is_cf_inst())
    467 			++s.cf_count;
    468 		else if (n->is_region()) {
    469 			++s.region_count;
    470 			region_node *r = static_cast<region_node*>(n);
    471 			if(r->is_loop())
    472 				++s.loop_count;
    473 
    474 			if (r->phi)
    475 				s.phi_count += r->phi->count();
    476 			if (r->loop_phi)
    477 				s.loop_phi_count += r->loop_phi->count();
    478 		}
    479 		else if (n->is_depart())
    480 			++s.depart_count;
    481 		else if (n->is_repeat())
    482 			++s.repeat_count;
    483 		else if (n->is_if())
    484 			++s.if_count;
    485 	}
    486 }
    487 
    488 void region_node::expand_depart(depart_node *d) {
    489 	depart_vec::iterator I = departs.begin() + d->dep_id, E;
    490 	I = departs.erase(I);
    491 	E = departs.end();
    492 	while (I != E) {
    493 		--(*I)->dep_id;
    494 		++I;
    495 	}
    496 	d->expand();
    497 }
    498 
    499 void region_node::expand_repeat(repeat_node *r) {
    500 	repeat_vec::iterator I = repeats.begin() + r->rep_id - 1, E;
    501 	I = repeats.erase(I);
    502 	E = repeats.end();
    503 	while (I != E) {
    504 		--(*I)->rep_id;
    505 		++I;
    506 	}
    507 	r->expand();
    508 }
    509 
    510 void node_stats::dump() {
    511 	sblog << "  alu_count : " << alu_count << "\n";
    512 	sblog << "  alu_kill_count : " << alu_kill_count << "\n";
    513 	sblog << "  alu_copy_mov_count : " << alu_copy_mov_count << "\n";
    514 	sblog << "  cf_count : " << cf_count << "\n";
    515 	sblog << "  fetch_count : " << fetch_count << "\n";
    516 	sblog << "  region_count : " << region_count << "\n";
    517 	sblog << "  loop_count : " << loop_count << "\n";
    518 	sblog << "  phi_count : " << phi_count << "\n";
    519 	sblog << "  loop_phi_count : " << loop_phi_count << "\n";
    520 	sblog << "  depart_count : " << depart_count << "\n";
    521 	sblog << "  repeat_count : " << repeat_count << "\n";
    522 	sblog << "  if_count : " << if_count << "\n";
    523 }
    524 
    525 unsigned alu_node::interp_param() {
    526 	if (!(bc.op_ptr->flags & AF_INTERP))
    527 		return 0;
    528 	unsigned param;
    529 	if (bc.op_ptr->src_count == 2) {
    530 		param = src[1]->select.sel();
    531 	} else {
    532 		param = src[0]->select.sel();
    533 	}
    534 	return param + 1;
    535 }
    536 
    537 alu_group_node* alu_node::get_alu_group_node() {
    538 	node *p = parent;
    539 	if (p) {
    540 		if (p->subtype == NST_ALU_PACKED_INST) {
    541 			assert(p->parent && p->parent->subtype == NST_ALU_GROUP);
    542 			p = p->parent;
    543 		}
    544 		return static_cast<alu_group_node*>(p);
    545 	}
    546 	return NULL;
    547 }
    548 
    549 } // namespace r600_sb
    550