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