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 | #ifndef R600_SB_IR_H_ |
||
28 | #define R600_SB_IR_H_ |
||
29 | |||
30 | #include |
||
31 | #include |
||
32 | #include |
||
33 | #include |
||
34 | #include |
||
35 | |||
36 | #include "sb_bc.h" |
||
37 | |||
38 | namespace r600_sb { |
||
39 | |||
40 | enum special_regs { |
||
41 | SV_ALU_PRED = 128, |
||
42 | SV_EXEC_MASK, |
||
43 | SV_AR_INDEX, |
||
44 | SV_VALID_MASK |
||
45 | }; |
||
46 | |||
47 | class node; |
||
48 | class value; |
||
49 | class shader; |
||
50 | |||
51 | struct sel_chan |
||
52 | { |
||
53 | unsigned id; |
||
54 | |||
55 | sel_chan(unsigned id = 0) : id(id) {} |
||
56 | sel_chan(unsigned sel, unsigned chan) : id(((sel << 2) | chan) + 1) {} |
||
57 | |||
58 | unsigned sel() const { return sel(id); } |
||
59 | unsigned chan() const {return chan(id); } |
||
60 | operator unsigned() const {return id;} |
||
61 | |||
62 | static unsigned sel(unsigned idx) { return (idx-1) >> 2; } |
||
63 | static unsigned chan(unsigned idx) { return (idx-1) & 3; } |
||
64 | }; |
||
65 | |||
66 | inline sb_ostream& operator <<(sb_ostream& o, sel_chan r) { |
||
67 | static const char * ch = "xyzw"; |
||
68 | o << r.sel() << "." << ch[r.chan()]; |
||
69 | return o; |
||
70 | } |
||
71 | |||
72 | typedef std::vector |
||
73 | |||
74 | class sb_pool { |
||
75 | protected: |
||
76 | static const unsigned SB_POOL_ALIGN = 8; |
||
77 | static const unsigned SB_POOL_DEFAULT_BLOCK_SIZE = (1 << 16); |
||
78 | |||
79 | typedef std::vector |
||
80 | |||
81 | unsigned block_size; |
||
82 | block_vector blocks; |
||
83 | unsigned total_size; |
||
84 | |||
85 | public: |
||
86 | sb_pool(unsigned block_size = SB_POOL_DEFAULT_BLOCK_SIZE) |
||
87 | : block_size(block_size), blocks(), total_size() {} |
||
88 | |||
89 | virtual ~sb_pool() { free_all(); } |
||
90 | |||
91 | void* allocate(unsigned sz); |
||
92 | |||
93 | protected: |
||
94 | void free_all(); |
||
95 | }; |
||
96 | |||
97 | template |
||
98 | class sb_set { |
||
99 | typedef std::vector |
||
100 | data_vector vec; |
||
101 | public: |
||
102 | |||
103 | typedef typename data_vector::iterator iterator; |
||
104 | typedef typename data_vector::const_iterator const_iterator; |
||
105 | |||
106 | sb_set() : vec() {} |
||
107 | ~sb_set() { } |
||
108 | |||
109 | iterator begin() { return vec.begin(); } |
||
110 | iterator end() { return vec.end(); } |
||
111 | const_iterator begin() const { return vec.begin(); } |
||
112 | const_iterator end() const { return vec.end(); } |
||
113 | |||
114 | void add_set(const sb_set& s) { |
||
115 | data_vector t; |
||
116 | t.reserve(vec.size() + s.vec.size()); |
||
117 | std::set_union(vec.begin(), vec.end(), s.vec.begin(), s.vec.end(), |
||
118 | std::inserter(t, t.begin()), Comp()); |
||
119 | vec.swap(t); |
||
120 | } |
||
121 | |||
122 | iterator lower_bound(const V& v) { |
||
123 | return std::lower_bound(vec.begin(), vec.end(), v, Comp()); |
||
124 | } |
||
125 | |||
126 | std::pair |
||
127 | iterator P = lower_bound(v); |
||
128 | if (P != vec.end() && is_equal(*P, v)) |
||
129 | return std::make_pair(P, false); |
||
130 | return std::make_pair(vec.insert(P, v), true); |
||
131 | } |
||
132 | |||
133 | unsigned erase(const V& v) { |
||
134 | iterator P = lower_bound(v); |
||
135 | if (P == vec.end() || !is_equal(*P, v)) |
||
136 | return 0; |
||
137 | vec.erase(P); |
||
138 | return 1; |
||
139 | } |
||
140 | |||
141 | void clear() { vec.clear(); } |
||
142 | |||
143 | bool empty() { return vec.empty(); } |
||
144 | |||
145 | bool is_equal(const V& v1, const V& v2) { |
||
146 | return !Comp()(v1, v2) && !Comp()(v2, v1); |
||
147 | } |
||
148 | |||
149 | iterator find(const V& v) { |
||
150 | iterator P = lower_bound(v); |
||
151 | return (P != vec.end() && is_equal(*P, v)) ? P : vec.end(); |
||
152 | } |
||
153 | |||
154 | unsigned size() { return vec.size(); } |
||
155 | void erase(iterator I) { vec.erase(I); } |
||
156 | }; |
||
157 | |||
158 | template |
||
159 | class sb_map { |
||
160 | typedef std::pair |
||
161 | |||
162 | struct Comp { |
||
163 | bool operator()(const datatype &v1, const datatype &v2) { |
||
164 | return KComp()(v1.first, v2.first); |
||
165 | } |
||
166 | }; |
||
167 | |||
168 | typedef sb_set |
||
169 | |||
170 | dataset set; |
||
171 | |||
172 | public: |
||
173 | |||
174 | sb_map() : set() {} |
||
175 | |||
176 | typedef typename dataset::iterator iterator; |
||
177 | |||
178 | iterator begin() { return set.begin(); } |
||
179 | iterator end() { return set.end(); } |
||
180 | |||
181 | void clear() { set.clear(); } |
||
182 | |||
183 | V& operator[](const K& key) { |
||
184 | datatype P = std::make_pair(key, V()); |
||
185 | iterator F = set.find(P); |
||
186 | if (F == set.end()) { |
||
187 | return (*(set.insert(P).first)).second; |
||
188 | } else { |
||
189 | return (*F).second; |
||
190 | } |
||
191 | } |
||
192 | |||
193 | std::pair |
||
194 | return set.insert(d); |
||
195 | } |
||
196 | |||
197 | iterator find(const K& key) { |
||
198 | return set.find(std::make_pair(key, V())); |
||
199 | } |
||
200 | |||
201 | unsigned erase(const K& key) { |
||
202 | return set.erase(std::make_pair(key, V())); |
||
203 | } |
||
204 | |||
205 | void erase(iterator I) { |
||
206 | set.erase(I); |
||
207 | } |
||
208 | }; |
||
209 | |||
210 | class sb_bitset { |
||
211 | typedef uint32_t basetype; |
||
212 | static const unsigned bt_bits = sizeof(basetype) << 3; |
||
213 | std::vector |
||
214 | unsigned bit_size; |
||
215 | |||
216 | public: |
||
217 | |||
218 | sb_bitset() : data(), bit_size() {} |
||
219 | |||
220 | bool get(unsigned id); |
||
221 | void set(unsigned id, bool bit = true); |
||
222 | bool set_chk(unsigned id, bool bit = true); |
||
223 | |||
224 | void clear(); |
||
225 | void resize(unsigned size); |
||
226 | |||
227 | unsigned size() { return bit_size; } |
||
228 | |||
229 | unsigned find_bit(unsigned start = 0); |
||
230 | |||
231 | void swap(sb_bitset & bs2); |
||
232 | |||
233 | bool operator==(const sb_bitset &bs2); |
||
234 | bool operator!=(const sb_bitset &bs2) { return !(*this == bs2); } |
||
235 | |||
236 | sb_bitset& operator|=(const sb_bitset &bs2) { |
||
237 | if (bit_size < bs2.bit_size) { |
||
238 | resize(bs2.bit_size); |
||
239 | } |
||
240 | |||
241 | for (unsigned i = 0, c = std::min(data.size(), bs2.data.size()); i < c; |
||
242 | ++i) { |
||
243 | data[i] |= bs2.data[i]; |
||
244 | } |
||
245 | return *this; |
||
246 | } |
||
247 | |||
248 | sb_bitset& operator&=(const sb_bitset &bs2); |
||
249 | sb_bitset& mask(const sb_bitset &bs2); |
||
250 | |||
251 | friend sb_bitset operator|(const sb_bitset &b1, const sb_bitset &b2) { |
||
252 | sb_bitset nbs(b1); |
||
253 | nbs |= b2; |
||
254 | return nbs; |
||
255 | } |
||
256 | }; |
||
257 | |||
258 | class value; |
||
259 | |||
260 | enum value_kind { |
||
261 | VLK_REG, |
||
262 | VLK_REL_REG, |
||
263 | VLK_SPECIAL_REG, |
||
264 | VLK_TEMP, |
||
265 | |||
266 | VLK_CONST, |
||
267 | VLK_KCACHE, |
||
268 | VLK_PARAM, |
||
269 | VLK_SPECIAL_CONST, |
||
270 | |||
271 | VLK_UNDEF |
||
272 | }; |
||
273 | |||
274 | |||
275 | |||
276 | class sb_value_pool : protected sb_pool { |
||
277 | unsigned aligned_elt_size; |
||
278 | |||
279 | public: |
||
280 | sb_value_pool(unsigned elt_size, unsigned block_elts = 256) |
||
281 | : sb_pool(block_elts * (aligned_elt_size = ((elt_size + |
||
282 | SB_POOL_ALIGN - 1) & ~(SB_POOL_ALIGN - 1)))) {} |
||
283 | |||
284 | virtual ~sb_value_pool() { delete_all(); } |
||
285 | |||
286 | value* create(value_kind k, sel_chan regid, unsigned ver); |
||
287 | |||
288 | value* operator[](unsigned id) { |
||
289 | unsigned offset = id * aligned_elt_size; |
||
290 | unsigned block_id; |
||
291 | if (offset < block_size) { |
||
292 | block_id = 0; |
||
293 | } else { |
||
294 | block_id = offset / block_size; |
||
295 | offset = offset % block_size; |
||
296 | } |
||
297 | return (value*)((char*)blocks[block_id] + offset); |
||
298 | } |
||
299 | |||
300 | unsigned size() { return total_size / aligned_elt_size; } |
||
301 | |||
302 | protected: |
||
303 | void delete_all(); |
||
304 | }; |
||
305 | |||
306 | |||
307 | |||
308 | |||
309 | |||
310 | class sb_value_set { |
||
311 | |||
312 | sb_bitset bs; |
||
313 | |||
314 | public: |
||
315 | sb_value_set() : bs() {} |
||
316 | |||
317 | class iterator { |
||
318 | sb_value_pool &vp; |
||
319 | sb_value_set *s; |
||
320 | unsigned nb; |
||
321 | public: |
||
322 | iterator(shader &sh, sb_value_set *s, unsigned nb = 0); |
||
323 | |||
324 | |||
325 | iterator& operator++() { |
||
326 | if (nb + 1 < s->bs.size()) |
||
327 | nb = s->bs.find_bit(nb + 1); |
||
328 | else |
||
329 | nb = s->bs.size(); |
||
330 | return *this; |
||
331 | } |
||
332 | bool operator !=(const iterator &i) { |
||
333 | return s != i.s || nb != i.nb; |
||
334 | } |
||
335 | bool operator ==(const iterator &i) { return !(*this != i); } |
||
336 | value* operator *() { |
||
337 | return vp[nb]; |
||
338 | } |
||
339 | |||
340 | |||
341 | }; |
||
342 | |||
343 | iterator begin(shader &sh) { |
||
344 | return iterator(sh, this, bs.size() ? bs.find_bit(0) : 0); |
||
345 | } |
||
346 | iterator end(shader &sh) { return iterator(sh, this, bs.size()); } |
||
347 | |||
348 | bool add_set_checked(sb_value_set & s2); |
||
349 | |||
350 | void add_set(sb_value_set & s2) { |
||
351 | if (bs.size() < s2.bs.size()) |
||
352 | bs.resize(s2.bs.size()); |
||
353 | bs |= s2.bs; |
||
354 | } |
||
355 | |||
356 | void remove_set(sb_value_set & s2); |
||
357 | |||
358 | bool add_vec(vvec &vv); |
||
359 | |||
360 | bool add_val(value *v); |
||
361 | bool contains(value *v); |
||
362 | |||
363 | bool remove_val(value *v); |
||
364 | |||
365 | bool remove_vec(vvec &vv); |
||
366 | |||
367 | void clear(); |
||
368 | |||
369 | bool empty(); |
||
370 | }; |
||
371 | |||
372 | typedef sb_value_set val_set; |
||
373 | |||
374 | struct gpr_array { |
||
375 | sel_chan base_gpr; // original gpr |
||
376 | sel_chan gpr; // assigned by regalloc |
||
377 | unsigned array_size; |
||
378 | |||
379 | gpr_array(sel_chan base_gpr, unsigned array_size) : base_gpr(base_gpr), |
||
380 | array_size(array_size) {} |
||
381 | |||
382 | unsigned hash() { return (base_gpr << 10) * array_size; } |
||
383 | |||
384 | val_set interferences; |
||
385 | vvec refs; |
||
386 | |||
387 | bool is_dead(); |
||
388 | |||
389 | }; |
||
390 | |||
391 | typedef std::vector |
||
392 | |||
393 | enum value_flags { |
||
394 | VLF_UNDEF = (1 << 0), |
||
395 | VLF_READONLY = (1 << 1), |
||
396 | VLF_DEAD = (1 << 2), |
||
397 | |||
398 | VLF_PIN_REG = (1 << 3), |
||
399 | VLF_PIN_CHAN = (1 << 4), |
||
400 | |||
401 | // opposite to alu clause local value - goes through alu clause boundary |
||
402 | // (can't use temp gpr, can't recolor in the alu scheduler, etc) |
||
403 | VLF_GLOBAL = (1 << 5), |
||
404 | VLF_FIXED = (1 << 6), |
||
405 | VLF_PVPS = (1 << 7), |
||
406 | |||
407 | VLF_PREALLOC = (1 << 8) |
||
408 | }; |
||
409 | |||
410 | inline value_flags operator |(value_flags l, value_flags r) { |
||
411 | return (value_flags)((unsigned)l|(unsigned)r); |
||
412 | } |
||
413 | inline value_flags operator &(value_flags l, value_flags r) { |
||
414 | return (value_flags)((unsigned)l&(unsigned)r); |
||
415 | } |
||
416 | inline value_flags operator ~(value_flags l) { |
||
417 | return (value_flags)(~(unsigned)l); |
||
418 | } |
||
419 | inline value_flags& operator |=(value_flags &l, value_flags r) { |
||
420 | l = l | r; |
||
421 | return l; |
||
422 | } |
||
423 | inline value_flags& operator &=(value_flags &l, value_flags r) { |
||
424 | l = l & r; |
||
425 | return l; |
||
426 | } |
||
427 | |||
428 | struct value; |
||
429 | |||
430 | sb_ostream& operator << (sb_ostream &o, value &v); |
||
431 | |||
432 | typedef uint32_t value_hash; |
||
433 | |||
434 | enum use_kind { |
||
435 | UK_SRC, |
||
436 | UK_SRC_REL, |
||
437 | UK_DST_REL, |
||
438 | UK_MAYDEF, |
||
439 | UK_MAYUSE, |
||
440 | UK_PRED, |
||
441 | UK_COND |
||
442 | }; |
||
443 | |||
444 | struct use_info { |
||
445 | use_info *next; |
||
446 | node *op; |
||
447 | use_kind kind; |
||
448 | int arg; |
||
449 | |||
450 | use_info(node *n, use_kind kind, int arg, use_info* next) |
||
451 | : next(next), op(n), kind(kind), arg(arg) {} |
||
452 | }; |
||
453 | |||
454 | enum constraint_kind { |
||
455 | CK_SAME_REG, |
||
456 | CK_PACKED_BS, |
||
457 | CK_PHI |
||
458 | }; |
||
459 | |||
460 | class shader; |
||
461 | class sb_value_pool; |
||
462 | class ra_chunk; |
||
463 | class ra_constraint; |
||
464 | |||
465 | class value { |
||
466 | protected: |
||
467 | value(unsigned sh_id, value_kind k, sel_chan select, unsigned ver = 0) |
||
468 | : kind(k), flags(), |
||
469 | rel(), array(), |
||
470 | version(ver), select(select), pin_gpr(select), gpr(), |
||
471 | gvn_source(), ghash(), |
||
472 | def(), adef(), uses(), constraint(), chunk(), |
||
473 | literal_value(), uid(sh_id) {} |
||
474 | |||
475 | ~value() { delete_uses(); } |
||
476 | |||
477 | friend class sb_value_pool; |
||
478 | public: |
||
479 | value_kind kind; |
||
480 | value_flags flags; |
||
481 | |||
482 | vvec mdef; |
||
483 | vvec muse; |
||
484 | value *rel; |
||
485 | gpr_array *array; |
||
486 | |||
487 | unsigned version; |
||
488 | |||
489 | sel_chan select; |
||
490 | sel_chan pin_gpr; |
||
491 | sel_chan gpr; |
||
492 | |||
493 | value *gvn_source; |
||
494 | value_hash ghash; |
||
495 | |||
496 | node *def, *adef; |
||
497 | use_info *uses; |
||
498 | |||
499 | ra_constraint *constraint; |
||
500 | ra_chunk *chunk; |
||
501 | |||
502 | literal literal_value; |
||
503 | |||
504 | bool is_const() { return kind == VLK_CONST || kind == VLK_UNDEF; } |
||
505 | |||
506 | bool is_AR() { |
||
507 | return is_special_reg() && select == sel_chan(SV_AR_INDEX, 0); |
||
508 | } |
||
509 | |||
510 | node* any_def() { |
||
511 | assert(!(def && adef)); |
||
512 | return def ? def : adef; |
||
513 | } |
||
514 | |||
515 | value* gvalue() { |
||
516 | value *v = this; |
||
517 | while (v->gvn_source && v != v->gvn_source) |
||
518 | // FIXME we really shouldn't have such chains |
||
519 | v = v->gvn_source; |
||
520 | return v; |
||
521 | } |
||
522 | |||
523 | bool is_float_0_or_1() { |
||
524 | value *v = gvalue(); |
||
525 | return v->is_const() && (v->literal_value == literal(0) |
||
526 | || v->literal_value == literal(1.0f)); |
||
527 | } |
||
528 | |||
529 | bool is_undef() { return gvalue()->kind == VLK_UNDEF; } |
||
530 | |||
531 | bool is_any_gpr() { |
||
532 | return (kind == VLK_REG || kind == VLK_TEMP); |
||
533 | } |
||
534 | |||
535 | bool is_agpr() { |
||
536 | return array && is_any_gpr(); |
||
537 | } |
||
538 | |||
539 | // scalar gpr, as opposed to element of gpr array |
||
540 | bool is_sgpr() { |
||
541 | return !array && is_any_gpr(); |
||
542 | } |
||
543 | |||
544 | bool is_special_reg() { return kind == VLK_SPECIAL_REG; } |
||
545 | bool is_any_reg() { return is_any_gpr() || is_special_reg(); } |
||
546 | bool is_kcache() { return kind == VLK_KCACHE; } |
||
547 | bool is_rel() { return kind == VLK_REL_REG; } |
||
548 | bool is_readonly() { return flags & VLF_READONLY; } |
||
549 | |||
550 | bool is_chan_pinned() { return flags & VLF_PIN_CHAN; } |
||
551 | bool is_reg_pinned() { return flags & VLF_PIN_REG; } |
||
552 | |||
553 | bool is_global(); |
||
554 | void set_global(); |
||
555 | void set_prealloc(); |
||
556 | |||
557 | bool is_prealloc(); |
||
558 | |||
559 | bool is_fixed(); |
||
560 | void fix(); |
||
561 | |||
562 | bool is_dead() { return flags & VLF_DEAD; } |
||
563 | |||
564 | literal & get_const_value() { |
||
565 | value *v = gvalue(); |
||
566 | assert(v->is_const()); |
||
567 | return v->literal_value; |
||
568 | } |
||
569 | |||
570 | // true if needs to be encoded as literal in alu |
||
571 | bool is_literal() { |
||
572 | return is_const() |
||
573 | && literal_value != literal(0) |
||
574 | && literal_value != literal(1) |
||
575 | && literal_value != literal(-1) |
||
576 | && literal_value != literal(0.5) |
||
577 | && literal_value != literal(1.0); |
||
578 | } |
||
579 | |||
580 | void add_use(node *n, use_kind kind, int arg); |
||
581 | |||
582 | value_hash hash(); |
||
583 | value_hash rel_hash(); |
||
584 | |||
585 | void assign_source(value *v) { |
||
586 | assert(!gvn_source || gvn_source == this); |
||
587 | gvn_source = v->gvalue(); |
||
588 | } |
||
589 | |||
590 | bool v_equal(value *v) { return gvalue() == v->gvalue(); } |
||
591 | |||
592 | unsigned use_count(); |
||
593 | void delete_uses(); |
||
594 | |||
595 | sel_chan get_final_gpr() { |
||
596 | if (array && array->gpr) { |
||
597 | int reg_offset = select.sel() - array->base_gpr.sel(); |
||
598 | if (rel && rel->is_const()) |
||
599 | reg_offset += rel->get_const_value().i; |
||
600 | return array->gpr + (reg_offset << 2); |
||
601 | } else { |
||
602 | return gpr; |
||
603 | } |
||
604 | } |
||
605 | |||
606 | unsigned get_final_chan() { |
||
607 | if (array) { |
||
608 | assert(array->gpr); |
||
609 | return array->gpr.chan(); |
||
610 | } else { |
||
611 | assert(gpr); |
||
612 | return gpr.chan(); |
||
613 | } |
||
614 | } |
||
615 | |||
616 | val_set interferences; |
||
617 | unsigned uid; |
||
618 | }; |
||
619 | |||
620 | class expr_handler; |
||
621 | |||
622 | class value_table { |
||
623 | typedef std::vector |
||
624 | typedef std::vector |
||
625 | |||
626 | expr_handler &ex; |
||
627 | |||
628 | unsigned size_bits; |
||
629 | unsigned size; |
||
630 | unsigned size_mask; |
||
631 | |||
632 | vt_table hashtable; |
||
633 | |||
634 | unsigned cnt; |
||
635 | |||
636 | public: |
||
637 | |||
638 | value_table(expr_handler &ex, unsigned size_bits = 10) |
||
639 | : ex(ex), size_bits(size_bits), size(1u << size_bits), |
||
640 | size_mask(size - 1), hashtable(size), cnt() {} |
||
641 | |||
642 | ~value_table() {} |
||
643 | |||
644 | void add_value(value* v); |
||
645 | |||
646 | bool expr_equal(value* l, value* r); |
||
647 | |||
648 | unsigned count() { return cnt; } |
||
649 | |||
650 | void get_values(vvec & v); |
||
651 | }; |
||
652 | |||
653 | class sb_context; |
||
654 | |||
655 | enum node_type { |
||
656 | NT_UNKNOWN, |
||
657 | NT_LIST, |
||
658 | NT_OP, |
||
659 | NT_REGION, |
||
660 | NT_REPEAT, |
||
661 | NT_DEPART, |
||
662 | NT_IF, |
||
663 | }; |
||
664 | |||
665 | enum node_subtype { |
||
666 | NST_UNKNOWN, |
||
667 | NST_LIST, |
||
668 | NST_ALU_GROUP, |
||
669 | NST_ALU_CLAUSE, |
||
670 | NST_ALU_INST, |
||
671 | NST_ALU_PACKED_INST, |
||
672 | NST_CF_INST, |
||
673 | NST_FETCH_INST, |
||
674 | NST_TEX_CLAUSE, |
||
675 | NST_VTX_CLAUSE, |
||
676 | |||
677 | NST_BB, |
||
678 | |||
679 | NST_PHI, |
||
680 | NST_PSI, |
||
681 | NST_COPY, |
||
682 | |||
683 | NST_LOOP_PHI_CONTAINER, |
||
684 | NST_LOOP_CONTINUE, |
||
685 | NST_LOOP_BREAK |
||
686 | }; |
||
687 | |||
688 | enum node_flags { |
||
689 | NF_EMPTY = 0, |
||
690 | NF_DEAD = (1 << 0), |
||
691 | NF_REG_CONSTRAINT = (1 << 1), |
||
692 | NF_CHAN_CONSTRAINT = (1 << 2), |
||
693 | NF_ALU_4SLOT = (1 << 3), |
||
694 | NF_CONTAINER = (1 << 4), |
||
695 | |||
696 | NF_COPY_MOV = (1 << 5), |
||
697 | |||
698 | NF_DONT_KILL = (1 << 6), |
||
699 | NF_DONT_HOIST = (1 << 7), |
||
700 | NF_DONT_MOVE = (1 << 8), |
||
701 | |||
702 | // for KILLxx - we want to schedule them as early as possible |
||
703 | NF_SCHEDULE_EARLY = (1 << 9) |
||
704 | }; |
||
705 | |||
706 | inline node_flags operator |(node_flags l, node_flags r) { |
||
707 | return (node_flags)((unsigned)l|(unsigned)r); |
||
708 | } |
||
709 | inline node_flags& operator |=(node_flags &l, node_flags r) { |
||
710 | l = l | r; |
||
711 | return l; |
||
712 | } |
||
713 | |||
714 | inline node_flags& operator &=(node_flags &l, node_flags r) { |
||
715 | l = (node_flags)((unsigned)l & (unsigned)r); |
||
716 | return l; |
||
717 | } |
||
718 | |||
719 | inline node_flags operator ~(node_flags r) { |
||
720 | return (node_flags)~(unsigned)r; |
||
721 | } |
||
722 | |||
723 | struct node_stats { |
||
724 | unsigned alu_count; |
||
725 | unsigned alu_kill_count; |
||
726 | unsigned alu_copy_mov_count; |
||
727 | unsigned cf_count; |
||
728 | unsigned fetch_count; |
||
729 | unsigned region_count; |
||
730 | unsigned loop_count; |
||
731 | unsigned phi_count; |
||
732 | unsigned loop_phi_count; |
||
733 | unsigned depart_count; |
||
734 | unsigned repeat_count; |
||
735 | unsigned if_count; |
||
736 | |||
737 | node_stats() : alu_count(), alu_kill_count(), alu_copy_mov_count(), |
||
738 | cf_count(), fetch_count(), region_count(), |
||
739 | loop_count(), phi_count(), loop_phi_count(), depart_count(), |
||
740 | repeat_count(), if_count() {} |
||
741 | |||
742 | void dump(); |
||
743 | }; |
||
744 | |||
745 | class shader; |
||
746 | |||
747 | class vpass; |
||
748 | |||
749 | class container_node; |
||
750 | class region_node; |
||
751 | |||
752 | class node { |
||
753 | |||
754 | protected: |
||
755 | node(node_type nt, node_subtype nst, node_flags flags = NF_EMPTY) |
||
756 | : prev(), next(), parent(), |
||
757 | type(nt), subtype(nst), flags(flags), |
||
758 | pred(), dst(), src() {} |
||
759 | |||
760 | virtual ~node() {}; |
||
761 | |||
762 | public: |
||
763 | node *prev, *next; |
||
764 | container_node *parent; |
||
765 | |||
766 | node_type type; |
||
767 | node_subtype subtype; |
||
768 | node_flags flags; |
||
769 | |||
770 | value *pred; |
||
771 | |||
772 | vvec dst; |
||
773 | vvec src; |
||
774 | |||
775 | virtual bool is_valid() { return true; } |
||
776 | virtual bool accept(vpass &p, bool enter); |
||
777 | |||
778 | void insert_before(node *n); |
||
779 | void insert_after(node *n); |
||
780 | void replace_with(node *n); |
||
781 | void remove(); |
||
782 | |||
783 | virtual value_hash hash(); |
||
784 | value_hash hash_src(); |
||
785 | |||
786 | virtual bool fold_dispatch(expr_handler *ex); |
||
787 | |||
788 | bool is_container() { return flags & NF_CONTAINER; } |
||
789 | |||
790 | bool is_alu_packed() { return subtype == NST_ALU_PACKED_INST; } |
||
791 | bool is_alu_inst() { return subtype == NST_ALU_INST; } |
||
792 | bool is_alu_group() { return subtype == NST_ALU_GROUP; } |
||
793 | bool is_alu_clause() { return subtype == NST_ALU_CLAUSE; } |
||
794 | |||
795 | bool is_fetch_clause() { |
||
796 | return subtype == NST_TEX_CLAUSE || subtype == NST_VTX_CLAUSE; |
||
797 | } |
||
798 | |||
799 | bool is_copy() { return subtype == NST_COPY; } |
||
800 | bool is_copy_mov() { return flags & NF_COPY_MOV; } |
||
801 | bool is_any_alu() { return is_alu_inst() || is_alu_packed() || is_copy(); } |
||
802 | |||
803 | bool is_fetch_inst() { return subtype == NST_FETCH_INST; } |
||
804 | bool is_cf_inst() { return subtype == NST_CF_INST; } |
||
805 | |||
806 | bool is_region() { return type == NT_REGION; } |
||
807 | bool is_depart() { return type == NT_DEPART; } |
||
808 | bool is_repeat() { return type == NT_REPEAT; } |
||
809 | bool is_if() { return type == NT_IF; } |
||
810 | bool is_bb() { return subtype == NST_BB; } |
||
811 | |||
812 | bool is_phi() { return subtype == NST_PHI; } |
||
813 | |||
814 | bool is_dead() { return flags & NF_DEAD; } |
||
815 | |||
816 | bool is_cf_op(unsigned op); |
||
817 | bool is_alu_op(unsigned op); |
||
818 | bool is_fetch_op(unsigned op); |
||
819 | |||
820 | unsigned cf_op_flags(); |
||
821 | unsigned alu_op_flags(); |
||
822 | unsigned alu_op_slot_flags(); |
||
823 | unsigned fetch_op_flags(); |
||
824 | |||
825 | bool is_mova(); |
||
826 | bool is_pred_set(); |
||
827 | |||
828 | bool vec_uses_ar(vvec &vv) { |
||
829 | for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) { |
||
830 | value *v = *I; |
||
831 | if (v && v->rel && !v->rel->is_const()) |
||
832 | return true; |
||
833 | } |
||
834 | return false; |
||
835 | } |
||
836 | |||
837 | bool uses_ar() { |
||
838 | return vec_uses_ar(dst) || vec_uses_ar(src); |
||
839 | } |
||
840 | |||
841 | |||
842 | region_node* get_parent_region(); |
||
843 | |||
844 | friend class shader; |
||
845 | }; |
||
846 | |||
847 | class container_node : public node { |
||
848 | public: |
||
849 | |||
850 | container_node(node_type nt = NT_LIST, node_subtype nst = NST_LIST, |
||
851 | node_flags flags = NF_EMPTY) |
||
852 | : node(nt, nst, flags | NF_CONTAINER), first(), last(), |
||
853 | live_after(), live_before() {} |
||
854 | |||
855 | // child items list |
||
856 | node *first, *last; |
||
857 | |||
858 | val_set live_after; |
||
859 | val_set live_before; |
||
860 | |||
861 | class iterator { |
||
862 | node *p; |
||
863 | public: |
||
864 | iterator(node *pp = NULL) : p(pp) {} |
||
865 | iterator & operator ++() { p = p->next; return *this;} |
||
866 | iterator & operator --() { p = p->prev; return *this;} |
||
867 | node* operator *() { return p; } |
||
868 | node* operator ->() { return p; } |
||
869 | const iterator advance(int n) { |
||
870 | if (!n) return *this; |
||
871 | iterator I(p); |
||
872 | if (n > 0) while (n--) ++I; |
||
873 | else while (n++) --I; |
||
874 | return I; |
||
875 | } |
||
876 | const iterator operator +(int n) { return advance(n); } |
||
877 | const iterator operator -(int n) { return advance(-n); } |
||
878 | bool operator !=(const iterator &i) { return p != i.p; } |
||
879 | bool operator ==(const iterator &i) { return p == i.p; } |
||
880 | }; |
||
881 | |||
882 | class riterator { |
||
883 | iterator i; |
||
884 | public: |
||
885 | riterator(node *p = NULL) : i(p) {} |
||
886 | riterator & operator ++() { --i; return *this;} |
||
887 | riterator & operator --() { ++i; return *this;} |
||
888 | node* operator *() { return *i; } |
||
889 | node* operator ->() { return *i; } |
||
890 | bool operator !=(const riterator &r) { return i != r.i; } |
||
891 | bool operator ==(const riterator &r) { return i == r.i; } |
||
892 | }; |
||
893 | |||
894 | iterator begin() { return first; } |
||
895 | iterator end() { return NULL; } |
||
896 | riterator rbegin() { return last; } |
||
897 | riterator rend() { return NULL; } |
||
898 | |||
899 | bool empty() { assert(first != NULL || first == last); return !first; } |
||
900 | unsigned count(); |
||
901 | |||
902 | // used with node containers that represent shceduling queues |
||
903 | // ignores copies and takes into account alu_packed_node items |
||
904 | unsigned real_alu_count(); |
||
905 | |||
906 | void push_back(node *n); |
||
907 | void push_front(node *n); |
||
908 | |||
909 | void insert_node_before(node *s, node *n); |
||
910 | void insert_node_after(node *s, node *n); |
||
911 | |||
912 | void append_from(container_node *c); |
||
913 | |||
914 | // remove range [b..e) from some container and assign to this container |
||
915 | void move(iterator b, iterator e); |
||
916 | |||
917 | void expand(); |
||
918 | void expand(container_node *n); |
||
919 | void remove_node(node *n); |
||
920 | |||
921 | node *cut(iterator b, iterator e); |
||
922 | |||
923 | void clear() { first = last = NULL; } |
||
924 | |||
925 | virtual bool is_valid() { return true; } |
||
926 | virtual bool accept(vpass &p, bool enter); |
||
927 | virtual bool fold_dispatch(expr_handler *ex); |
||
928 | |||
929 | node* front() { return first; } |
||
930 | node* back() { return last; } |
||
931 | |||
932 | void collect_stats(node_stats &s); |
||
933 | |||
934 | friend class shader; |
||
935 | |||
936 | |||
937 | }; |
||
938 | |||
939 | typedef container_node::iterator node_iterator; |
||
940 | typedef container_node::riterator node_riterator; |
||
941 | |||
942 | class alu_group_node : public container_node { |
||
943 | protected: |
||
944 | alu_group_node() : container_node(NT_LIST, NST_ALU_GROUP), literals() {} |
||
945 | public: |
||
946 | |||
947 | std::vector |
||
948 | |||
949 | virtual bool is_valid() { return subtype == NST_ALU_GROUP; } |
||
950 | virtual bool accept(vpass &p, bool enter); |
||
951 | |||
952 | |||
953 | unsigned literal_chan(literal l) { |
||
954 | std::vector |
||
955 | std::find(literals.begin(), literals.end(), l); |
||
956 | assert(F != literals.end()); |
||
957 | return F - literals.begin(); |
||
958 | } |
||
959 | |||
960 | friend class shader; |
||
961 | }; |
||
962 | |||
963 | class cf_node : public container_node { |
||
964 | protected: |
||
965 | cf_node() : container_node(NT_OP, NST_CF_INST), jump_target(), |
||
966 | jump_after_target() {}; |
||
967 | public: |
||
968 | bc_cf bc; |
||
969 | |||
970 | cf_node *jump_target; |
||
971 | bool jump_after_target; |
||
972 | |||
973 | virtual bool is_valid() { return subtype == NST_CF_INST; } |
||
974 | virtual bool accept(vpass &p, bool enter); |
||
975 | virtual bool fold_dispatch(expr_handler *ex); |
||
976 | |||
977 | void jump(cf_node *c) { jump_target = c; jump_after_target = false; } |
||
978 | void jump_after(cf_node *c) { jump_target = c; jump_after_target = true; } |
||
979 | |||
980 | friend class shader; |
||
981 | }; |
||
982 | |||
983 | class alu_node : public node { |
||
984 | protected: |
||
985 | alu_node() : node(NT_OP, NST_ALU_INST) {}; |
||
986 | public: |
||
987 | bc_alu bc; |
||
988 | |||
989 | virtual bool is_valid() { return subtype == NST_ALU_INST; } |
||
990 | virtual bool accept(vpass &p, bool enter); |
||
991 | virtual bool fold_dispatch(expr_handler *ex); |
||
992 | |||
993 | unsigned forced_bank_swizzle() { |
||
994 | return ((bc.op_ptr->flags & AF_INTERP) && (bc.slot_flags == AF_4V)) ? |
||
995 | VEC_210 : 0; |
||
996 | } |
||
997 | |||
998 | // return param index + 1 if instruction references interpolation param, |
||
999 | // otherwise 0 |
||
1000 | unsigned interp_param(); |
||
1001 | |||
1002 | alu_group_node *get_alu_group_node(); |
||
1003 | |||
1004 | friend class shader; |
||
1005 | }; |
||
1006 | |||
1007 | // for multi-slot instrs - DOT/INTERP/... (maybe useful for 64bit pairs later) |
||
1008 | class alu_packed_node : public container_node { |
||
1009 | protected: |
||
1010 | alu_packed_node() : container_node(NT_OP, NST_ALU_PACKED_INST) {} |
||
1011 | public: |
||
1012 | |||
1013 | const alu_op_info* op_ptr() { |
||
1014 | return static_cast |
||
1015 | } |
||
1016 | unsigned op() { return static_cast |
||
1017 | void init_args(bool repl); |
||
1018 | |||
1019 | virtual bool is_valid() { return subtype == NST_ALU_PACKED_INST; } |
||
1020 | virtual bool accept(vpass &p, bool enter); |
||
1021 | virtual bool fold_dispatch(expr_handler *ex); |
||
1022 | |||
1023 | unsigned get_slot_mask(); |
||
1024 | void update_packed_items(sb_context &ctx); |
||
1025 | |||
1026 | friend class shader; |
||
1027 | }; |
||
1028 | |||
1029 | class fetch_node : public node { |
||
1030 | protected: |
||
1031 | fetch_node() : node(NT_OP, NST_FETCH_INST) {}; |
||
1032 | public: |
||
1033 | bc_fetch bc; |
||
1034 | |||
1035 | virtual bool is_valid() { return subtype == NST_FETCH_INST; } |
||
1036 | virtual bool accept(vpass &p, bool enter); |
||
1037 | virtual bool fold_dispatch(expr_handler *ex); |
||
1038 | |||
1039 | bool uses_grad() { return bc.op_ptr->flags & FF_USEGRAD; } |
||
1040 | |||
1041 | friend class shader; |
||
1042 | }; |
||
1043 | |||
1044 | class region_node; |
||
1045 | |||
1046 | class repeat_node : public container_node { |
||
1047 | protected: |
||
1048 | repeat_node(region_node *target, unsigned id) |
||
1049 | : container_node(NT_REPEAT, NST_LIST), target(target), rep_id(id) {} |
||
1050 | public: |
||
1051 | region_node *target; |
||
1052 | unsigned rep_id; |
||
1053 | |||
1054 | virtual bool accept(vpass &p, bool enter); |
||
1055 | |||
1056 | friend class shader; |
||
1057 | }; |
||
1058 | |||
1059 | class depart_node : public container_node { |
||
1060 | protected: |
||
1061 | depart_node(region_node *target, unsigned id) |
||
1062 | : container_node(NT_DEPART, NST_LIST), target(target), dep_id(id) {} |
||
1063 | public: |
||
1064 | region_node *target; |
||
1065 | unsigned dep_id; |
||
1066 | |||
1067 | virtual bool accept(vpass &p, bool enter); |
||
1068 | |||
1069 | friend class shader; |
||
1070 | }; |
||
1071 | |||
1072 | class if_node : public container_node { |
||
1073 | protected: |
||
1074 | if_node() : container_node(NT_IF, NST_LIST), cond() {}; |
||
1075 | public: |
||
1076 | value *cond; // glued to pseudo output (dst[2]) of the PRED_SETxxx |
||
1077 | |||
1078 | virtual bool accept(vpass &p, bool enter); |
||
1079 | |||
1080 | friend class shader; |
||
1081 | }; |
||
1082 | |||
1083 | typedef std::vector |
||
1084 | typedef std::vector |
||
1085 | |||
1086 | class region_node : public container_node { |
||
1087 | protected: |
||
1088 | region_node(unsigned id) : container_node(NT_REGION, NST_LIST), region_id(id), |
||
1089 | loop_phi(), phi(), vars_defined(), departs(), repeats() {} |
||
1090 | public: |
||
1091 | unsigned region_id; |
||
1092 | |||
1093 | container_node *loop_phi; |
||
1094 | container_node *phi; |
||
1095 | |||
1096 | val_set vars_defined; |
||
1097 | |||
1098 | depart_vec departs; |
||
1099 | repeat_vec repeats; |
||
1100 | |||
1101 | virtual bool accept(vpass &p, bool enter); |
||
1102 | |||
1103 | unsigned dep_count() { return departs.size(); } |
||
1104 | unsigned rep_count() { return repeats.size() + 1; } |
||
1105 | |||
1106 | bool is_loop() { return !repeats.empty(); } |
||
1107 | |||
1108 | container_node* get_entry_code_location() { |
||
1109 | node *p = first; |
||
1110 | while (p && (p->is_depart() || p->is_repeat())) |
||
1111 | p = static_cast |
||
1112 | |||
1113 | container_node *c = static_cast |
||
1114 | if (c->is_bb()) |
||
1115 | return c; |
||
1116 | else |
||
1117 | return c->parent; |
||
1118 | } |
||
1119 | |||
1120 | void expand_depart(depart_node *d); |
||
1121 | void expand_repeat(repeat_node *r); |
||
1122 | |||
1123 | friend class shader; |
||
1124 | }; |
||
1125 | |||
1126 | class bb_node : public container_node { |
||
1127 | protected: |
||
1128 | bb_node(unsigned id, unsigned loop_level) |
||
1129 | : container_node(NT_LIST, NST_BB), id(id), loop_level(loop_level) {} |
||
1130 | public: |
||
1131 | unsigned id; |
||
1132 | unsigned loop_level; |
||
1133 | |||
1134 | virtual bool accept(vpass &p, bool enter); |
||
1135 | |||
1136 | friend class shader; |
||
1137 | }; |
||
1138 | |||
1139 | |||
1140 | typedef std::vector |
||
1141 | typedef std::vector |
||
1142 | typedef std::list |
||
1143 | typedef sched_queue::iterator sq_iterator; |
||
1144 | typedef std::vector |
||
1145 | typedef std::list |
||
1146 | typedef std::set |
||
1147 | |||
1148 | |||
1149 | |||
1150 | } // namespace r600_sb |
||
1151 | |||
1152 | #endif /* R600_SB_IR_H_ */><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>>>>>>><>><>><>><>><>(sb_ostream&><(sb_ostream&>><> |