Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* |
2 | * Copyright 2013 Vadim Girlin |
||
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 VT_DEBUG 0 |
||
28 | |||
29 | #if VT_DEBUG |
||
30 | #define VT_DUMP(q) do { q } while (0) |
||
31 | #else |
||
32 | #define VT_DUMP(q) |
||
33 | #endif |
||
34 | |||
35 | #include |
||
36 | |||
37 | #include "sb_shader.h" |
||
38 | #include "sb_pass.h" |
||
39 | |||
40 | namespace r600_sb { |
||
41 | |||
42 | static const char * chans = "xyzw01?_"; |
||
43 | |||
44 | sb_ostream& operator << (sb_ostream &o, value &v) { |
||
45 | |||
46 | bool dead = v.flags & VLF_DEAD; |
||
47 | |||
48 | if (dead) |
||
49 | o << "{"; |
||
50 | |||
51 | switch (v.kind) { |
||
52 | case VLK_SPECIAL_REG: { |
||
53 | switch (v.select.sel()) { |
||
54 | case SV_AR_INDEX: o << "AR"; break; |
||
55 | case SV_ALU_PRED: o << "PR"; break; |
||
56 | case SV_EXEC_MASK: o << "EM"; break; |
||
57 | case SV_VALID_MASK: o << "VM"; break; |
||
58 | default: o << "???specialreg"; break; |
||
59 | } |
||
60 | break; |
||
61 | } |
||
62 | |||
63 | case VLK_REG: |
||
64 | o << "R" << v.select.sel() << "." |
||
65 | << chans[v.select.chan()]; |
||
66 | |||
67 | break; |
||
68 | case VLK_KCACHE: { |
||
69 | o << "C" << v.select.sel() << "." << chans[v.select.chan()]; |
||
70 | } |
||
71 | break; |
||
72 | case VLK_CONST: |
||
73 | o << v.literal_value.f << "|"; |
||
74 | o.print_zw_hex(v.literal_value.u, 8); |
||
75 | break; |
||
76 | case VLK_PARAM: |
||
77 | o << "Param" << (v.select.sel() - ALU_SRC_PARAM_OFFSET) |
||
78 | << chans[v.select.chan()]; |
||
79 | break; |
||
80 | case VLK_TEMP: |
||
81 | o << "t" << v.select.sel() - shader::temp_regid_offset; |
||
82 | break; |
||
83 | case VLK_REL_REG: |
||
84 | |||
85 | o << "A" << v.select; |
||
86 | o << "["; |
||
87 | o << *v.rel; |
||
88 | o << "]"; |
||
89 | |||
90 | o << "_" << v.uid; |
||
91 | |||
92 | break; |
||
93 | case VLK_UNDEF: |
||
94 | o << "undef"; |
||
95 | break; |
||
96 | default: |
||
97 | o << v.kind << "?????"; |
||
98 | break; |
||
99 | } |
||
100 | |||
101 | if (v.version) |
||
102 | o << "." << v.version; |
||
103 | |||
104 | if (dead) |
||
105 | o << "}"; |
||
106 | |||
107 | if (v.is_global()) |
||
108 | o << "||"; |
||
109 | if (v.is_fixed()) |
||
110 | o << "F"; |
||
111 | if (v.is_prealloc()) |
||
112 | o << "P"; |
||
113 | |||
114 | sel_chan g; |
||
115 | |||
116 | if (v.is_rel()) { |
||
117 | g = v.array->gpr; |
||
118 | } else { |
||
119 | g = v.gpr; |
||
120 | } |
||
121 | |||
122 | if (g) { |
||
123 | o << "@R" << g.sel() << "." << chans[g.chan()]; |
||
124 | } |
||
125 | |||
126 | return o; |
||
127 | } |
||
128 | |||
129 | void value_table::add_value(value* v) { |
||
130 | |||
131 | if (v->gvn_source) { |
||
132 | return; |
||
133 | } |
||
134 | |||
135 | VT_DUMP( |
||
136 | sblog << "gvn add_value "; |
||
137 | dump::dump_val(v); |
||
138 | ); |
||
139 | |||
140 | value_hash hash = v->hash(); |
||
141 | vt_item & vti = hashtable[hash & size_mask]; |
||
142 | vti.push_back(v); |
||
143 | ++cnt; |
||
144 | |||
145 | if (v->def && ex.try_fold(v)) { |
||
146 | VT_DUMP( |
||
147 | sblog << " folded: "; |
||
148 | dump::dump_val(v->gvn_source); |
||
149 | sblog << "\n"; |
||
150 | ); |
||
151 | return; |
||
152 | } |
||
153 | |||
154 | int n = 0; |
||
155 | for (vt_item::iterator I = vti.begin(), E = vti.end(); I != E; ++I, ++n) { |
||
156 | value *c = *I; |
||
157 | |||
158 | if (c == v) |
||
159 | break; |
||
160 | |||
161 | if (expr_equal(c, v)) { |
||
162 | v->gvn_source = c->gvn_source; |
||
163 | |||
164 | VT_DUMP( |
||
165 | sblog << " found : equal to "; |
||
166 | dump::dump_val(v->gvn_source); |
||
167 | sblog << "\n"; |
||
168 | ); |
||
169 | return; |
||
170 | } |
||
171 | } |
||
172 | |||
173 | v->gvn_source = v; |
||
174 | VT_DUMP( |
||
175 | sblog << " added new\n"; |
||
176 | ); |
||
177 | } |
||
178 | |||
179 | value_hash value::hash() { |
||
180 | if (ghash) |
||
181 | return ghash; |
||
182 | if (is_rel()) |
||
183 | ghash = rel_hash(); |
||
184 | else if (def) |
||
185 | ghash = def->hash(); |
||
186 | else |
||
187 | ghash = ((uintptr_t)this) | 1; |
||
188 | |||
189 | return ghash; |
||
190 | } |
||
191 | |||
192 | value_hash value::rel_hash() { |
||
193 | value_hash h = rel ? rel->hash() : 0; |
||
194 | h |= select << 10; |
||
195 | h |= array->hash(); |
||
196 | return h; |
||
197 | } |
||
198 | |||
199 | bool value_table::expr_equal(value* l, value* r) { |
||
200 | return ex.equal(l, r); |
||
201 | } |
||
202 | |||
203 | void value_table::get_values(vvec& v) { |
||
204 | v.resize(cnt); |
||
205 | |||
206 | vvec::iterator T = v.begin(); |
||
207 | |||
208 | for(vt_table::iterator I = hashtable.begin(), E = hashtable.end(); |
||
209 | I != E; ++I) { |
||
210 | T = std::copy(I->begin(), I->end(), T); |
||
211 | } |
||
212 | } |
||
213 | |||
214 | void value::add_use(node* n, use_kind kind, int arg) { |
||
215 | if (0) { |
||
216 | sblog << "add_use "; |
||
217 | dump::dump_val(this); |
||
218 | sblog << " => "; |
||
219 | dump::dump_op(n); |
||
220 | sblog << " kind " << kind << " arg " << arg << "\n"; |
||
221 | } |
||
222 | uses = new use_info(n, kind, arg, uses); |
||
223 | } |
||
224 | |||
225 | unsigned value::use_count() { |
||
226 | use_info *u = uses; |
||
227 | unsigned c = 0; |
||
228 | while (u) { |
||
229 | ++c; |
||
230 | u = u->next; |
||
231 | } |
||
232 | return c; |
||
233 | } |
||
234 | |||
235 | bool value::is_global() { |
||
236 | if (chunk) |
||
237 | return chunk->is_global(); |
||
238 | return flags & VLF_GLOBAL; |
||
239 | } |
||
240 | |||
241 | void value::set_global() { |
||
242 | assert(is_sgpr()); |
||
243 | flags |= VLF_GLOBAL; |
||
244 | if (chunk) |
||
245 | chunk->set_global(); |
||
246 | } |
||
247 | |||
248 | void value::set_prealloc() { |
||
249 | assert(is_sgpr()); |
||
250 | flags |= VLF_PREALLOC; |
||
251 | if (chunk) |
||
252 | chunk->set_prealloc(); |
||
253 | } |
||
254 | |||
255 | bool value::is_fixed() { |
||
256 | if (array && array->gpr) |
||
257 | return true; |
||
258 | if (chunk) |
||
259 | return chunk->is_fixed(); |
||
260 | return flags & VLF_FIXED; |
||
261 | } |
||
262 | |||
263 | void value::fix() { |
||
264 | if (chunk) |
||
265 | chunk->fix(); |
||
266 | flags |= VLF_FIXED; |
||
267 | } |
||
268 | |||
269 | bool value::is_prealloc() { |
||
270 | if (chunk) |
||
271 | return chunk->is_prealloc(); |
||
272 | return flags & VLF_PREALLOC; |
||
273 | } |
||
274 | |||
275 | void value::delete_uses() { |
||
276 | use_info *u, *c = uses; |
||
277 | while (c) { |
||
278 | u = c->next; |
||
279 | delete c; |
||
280 | c = u; |
||
281 | } |
||
282 | uses = NULL; |
||
283 | } |
||
284 | |||
285 | void ra_constraint::update_values() { |
||
286 | for (vvec::iterator I = values.begin(), E = values.end(); I != E; ++I) { |
||
287 | assert(!(*I)->constraint); |
||
288 | (*I)->constraint = this; |
||
289 | } |
||
290 | } |
||
291 | |||
292 | void* sb_pool::allocate(unsigned sz) { |
||
293 | sz = (sz + SB_POOL_ALIGN - 1) & ~(SB_POOL_ALIGN - 1); |
||
294 | assert (sz < (block_size >> 6) && "too big allocation size for sb_pool"); |
||
295 | |||
296 | unsigned offset = total_size % block_size; |
||
297 | unsigned capacity = block_size * blocks.size(); |
||
298 | |||
299 | if (total_size + sz > capacity) { |
||
300 | total_size = capacity; |
||
301 | void * nb = malloc(block_size); |
||
302 | blocks.push_back(nb); |
||
303 | offset = 0; |
||
304 | } |
||
305 | |||
306 | total_size += sz; |
||
307 | return ((char*)blocks.back() + offset); |
||
308 | } |
||
309 | |||
310 | void sb_pool::free_all() { |
||
311 | for (block_vector::iterator I = blocks.begin(), E = blocks.end(); I != E; |
||
312 | ++I) { |
||
313 | free(*I); |
||
314 | } |
||
315 | } |
||
316 | |||
317 | value* sb_value_pool::create(value_kind k, sel_chan regid, |
||
318 | unsigned ver) { |
||
319 | void* np = allocate(aligned_elt_size); |
||
320 | value *v = new (np) value(size(), k, regid, ver); |
||
321 | return v; |
||
322 | } |
||
323 | |||
324 | void sb_value_pool::delete_all() { |
||
325 | unsigned bcnt = blocks.size(); |
||
326 | unsigned toffset = 0; |
||
327 | for (unsigned b = 0; b < bcnt; ++b) { |
||
328 | char *bstart = (char*)blocks[b]; |
||
329 | for (unsigned offset = 0; offset < block_size; |
||
330 | offset += aligned_elt_size) { |
||
331 | ((value*)(bstart + offset))->~value(); |
||
332 | toffset += aligned_elt_size; |
||
333 | if (toffset >= total_size) |
||
334 | return; |
||
335 | } |
||
336 | } |
||
337 | } |
||
338 | |||
339 | bool sb_bitset::get(unsigned id) { |
||
340 | assert(id < bit_size); |
||
341 | unsigned w = id / bt_bits; |
||
342 | unsigned b = id % bt_bits; |
||
343 | return (data[w] >> b) & 1; |
||
344 | } |
||
345 | |||
346 | void sb_bitset::set(unsigned id, bool bit) { |
||
347 | assert(id < bit_size); |
||
348 | unsigned w = id / bt_bits; |
||
349 | unsigned b = id % bt_bits; |
||
350 | if (w >= data.size()) |
||
351 | data.resize(w + 1); |
||
352 | |||
353 | if (bit) |
||
354 | data[w] |= (1 << b); |
||
355 | else |
||
356 | data[w] &= ~(1 << b); |
||
357 | } |
||
358 | |||
359 | inline bool sb_bitset::set_chk(unsigned id, bool bit) { |
||
360 | assert(id < bit_size); |
||
361 | unsigned w = id / bt_bits; |
||
362 | unsigned b = id % bt_bits; |
||
363 | basetype d = data[w]; |
||
364 | basetype dn = (d & ~(1 << b)) | (bit << b); |
||
365 | bool r = (d != dn); |
||
366 | data[w] = r ? dn : data[w]; |
||
367 | return r; |
||
368 | } |
||
369 | |||
370 | void sb_bitset::clear() { |
||
371 | std::fill(data.begin(), data.end(), 0); |
||
372 | } |
||
373 | |||
374 | void sb_bitset::resize(unsigned size) { |
||
375 | unsigned cur_data_size = data.size(); |
||
376 | unsigned new_data_size = (size + bt_bits - 1) / bt_bits; |
||
377 | |||
378 | |||
379 | if (new_data_size != cur_data_size) |
||
380 | data.resize(new_data_size); |
||
381 | |||
382 | // make sure that new bits in the existing word are cleared |
||
383 | if (cur_data_size && size > bit_size && bit_size % bt_bits) { |
||
384 | basetype clear_mask = (~(basetype)0u) << (bit_size % bt_bits); |
||
385 | data[cur_data_size - 1] &= ~clear_mask; |
||
386 | } |
||
387 | |||
388 | bit_size = size; |
||
389 | } |
||
390 | |||
391 | unsigned sb_bitset::find_bit(unsigned start) { |
||
392 | assert(start < bit_size); |
||
393 | unsigned w = start / bt_bits; |
||
394 | unsigned b = start % bt_bits; |
||
395 | unsigned sz = data.size(); |
||
396 | |||
397 | while (w < sz) { |
||
398 | basetype d = data[w] >> b; |
||
399 | if (d != 0) { |
||
400 | unsigned pos = __builtin_ctz(d) + b + w * bt_bits; |
||
401 | return pos; |
||
402 | } |
||
403 | |||
404 | b = 0; |
||
405 | ++w; |
||
406 | } |
||
407 | |||
408 | return bit_size; |
||
409 | } |
||
410 | |||
411 | sb_value_set::iterator::iterator(shader& sh, sb_value_set* s, unsigned nb) |
||
412 | : vp(sh.get_value_pool()), s(s), nb(nb) {} |
||
413 | |||
414 | bool sb_value_set::add_set_checked(sb_value_set& s2) { |
||
415 | if (bs.size() < s2.bs.size()) |
||
416 | bs.resize(s2.bs.size()); |
||
417 | sb_bitset nbs = bs | s2.bs; |
||
418 | if (bs != nbs) { |
||
419 | bs.swap(nbs); |
||
420 | return true; |
||
421 | } |
||
422 | return false; |
||
423 | } |
||
424 | |||
425 | void r600_sb::sb_value_set::remove_set(sb_value_set& s2) { |
||
426 | bs.mask(s2.bs); |
||
427 | } |
||
428 | |||
429 | bool sb_value_set::add_val(value* v) { |
||
430 | assert(v); |
||
431 | if (bs.size() < v->uid) |
||
432 | bs.resize(v->uid + 32); |
||
433 | |||
434 | return bs.set_chk(v->uid - 1, 1); |
||
435 | } |
||
436 | |||
437 | bool sb_value_set::remove_vec(vvec& vv) { |
||
438 | bool modified = false; |
||
439 | for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) { |
||
440 | if (*I) |
||
441 | modified |= remove_val(*I); |
||
442 | } |
||
443 | return modified; |
||
444 | } |
||
445 | |||
446 | void sb_value_set::clear() { |
||
447 | bs.clear(); |
||
448 | } |
||
449 | |||
450 | bool sb_value_set::remove_val(value* v) { |
||
451 | assert(v); |
||
452 | if (bs.size() < v->uid) |
||
453 | return false; |
||
454 | return bs.set_chk(v->uid - 1, 0); |
||
455 | } |
||
456 | |||
457 | bool r600_sb::sb_value_set::add_vec(vvec& vv) { |
||
458 | bool modified = false; |
||
459 | for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) { |
||
460 | value *v = *I; |
||
461 | if (v) |
||
462 | modified |= add_val(v); |
||
463 | } |
||
464 | return modified; |
||
465 | } |
||
466 | |||
467 | bool r600_sb::sb_value_set::contains(value* v) { |
||
468 | unsigned b = v->uid - 1; |
||
469 | if (b < bs.size()) |
||
470 | return bs.get(v->uid - 1); |
||
471 | else |
||
472 | return false; |
||
473 | } |
||
474 | |||
475 | bool sb_value_set::empty() { |
||
476 | return bs.size() == 0 || bs.find_bit(0) == bs.size(); |
||
477 | } |
||
478 | |||
479 | void sb_bitset::swap(sb_bitset& bs2) { |
||
480 | std::swap(data, bs2.data); |
||
481 | std::swap(bit_size, bs2.bit_size); |
||
482 | } |
||
483 | |||
484 | bool sb_bitset::operator ==(const sb_bitset& bs2) { |
||
485 | if (bit_size != bs2.bit_size) |
||
486 | return false; |
||
487 | |||
488 | for (unsigned i = 0, c = data.size(); i < c; ++i) { |
||
489 | if (data[i] != bs2.data[i]) |
||
490 | return false; |
||
491 | } |
||
492 | return true; |
||
493 | } |
||
494 | |||
495 | sb_bitset& sb_bitset::operator &=(const sb_bitset& bs2) { |
||
496 | if (bit_size > bs2.bit_size) { |
||
497 | resize(bs2.bit_size); |
||
498 | } |
||
499 | |||
500 | for (unsigned i = 0, c = std::min(data.size(), bs2.data.size()); i < c; |
||
501 | ++i) { |
||
502 | data[i] &= bs2.data[i]; |
||
503 | } |
||
504 | return *this; |
||
505 | } |
||
506 | |||
507 | sb_bitset& sb_bitset::mask(const sb_bitset& bs2) { |
||
508 | if (bit_size < bs2.bit_size) { |
||
509 | resize(bs2.bit_size); |
||
510 | } |
||
511 | |||
512 | for (unsigned i = 0, c = data.size(); i < c; |
||
513 | ++i) { |
||
514 | data[i] &= ~bs2.data[i]; |
||
515 | } |
||
516 | return *this; |
||
517 | } |
||
518 | |||
519 | bool ra_constraint::check() { |
||
520 | assert(kind == CK_SAME_REG); |
||
521 | |||
522 | unsigned reg = 0; |
||
523 | |||
524 | for (vvec::iterator I = values.begin(), E = values.end(); I != E; ++I) { |
||
525 | value *v = *I; |
||
526 | if (!v) |
||
527 | continue; |
||
528 | |||
529 | if (!v->gpr) |
||
530 | return false; |
||
531 | |||
532 | if (reg == 0) |
||
533 | reg = v->gpr.sel() + 1; |
||
534 | else if (reg != v->gpr.sel() + 1) |
||
535 | return false; |
||
536 | |||
537 | if (v->is_chan_pinned()) { |
||
538 | if (v->pin_gpr.chan() != v->gpr.chan()) |
||
539 | return false; |
||
540 | } |
||
541 | } |
||
542 | return true; |
||
543 | } |
||
544 | |||
545 | bool gpr_array::is_dead() { |
||
546 | return false; |
||
547 | } |
||
548 | |||
549 | } // namespace r600_sb>>>>>>>>>>><>><>><>>><>><>>>>>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><> |