1 /*
2 * Copyright 2011 Christoph Bumiller
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #ifndef __NV50_IR_UTIL_H__
24 #define __NV50_IR_UTIL_H__
25
26 #include <new>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <memory>
30 #include <map>
31
32 #ifndef NDEBUG
33 # include <typeinfo>
34 #endif
35
36 #include "util/u_inlines.h"
37 #include "util/u_memory.h"
38
39 #define ERROR(args...) _debug_printf("ERROR: " args)
40 #define WARN(args...) _debug_printf("WARNING: " args)
41 #define INFO(args...) _debug_printf(args)
42
43 #define INFO_DBG(m, f, args...) \
44 do { \
45 if (m & NV50_IR_DEBUG_##f) \
46 _debug_printf(args); \
47 } while(0)
48
49 #define FATAL(args...) \
50 do { \
51 fprintf(stderr, args); \
52 abort(); \
53 } while(0)
54
55
56 #define NV50_IR_FUNC_ALLOC_OBJ_DEF(obj, f, args...) \
57 new ((f)->getProgram()->mem_##obj.allocate()) obj(f, args)
58
59 #define new_Instruction(f, args...) \
60 NV50_IR_FUNC_ALLOC_OBJ_DEF(Instruction, f, args)
61 #define new_CmpInstruction(f, args...) \
62 NV50_IR_FUNC_ALLOC_OBJ_DEF(CmpInstruction, f, args)
63 #define new_TexInstruction(f, args...) \
64 NV50_IR_FUNC_ALLOC_OBJ_DEF(TexInstruction, f, args)
65 #define new_FlowInstruction(f, args...) \
66 NV50_IR_FUNC_ALLOC_OBJ_DEF(FlowInstruction, f, args)
67
68 #define new_LValue(f, args...) \
69 NV50_IR_FUNC_ALLOC_OBJ_DEF(LValue, f, args)
70
71
72 #define NV50_IR_PROG_ALLOC_OBJ_DEF(obj, p, args...) \
73 new ((p)->mem_##obj.allocate()) obj(p, args)
74
75 #define new_Symbol(p, args...) \
76 NV50_IR_PROG_ALLOC_OBJ_DEF(Symbol, p, args)
77 #define new_ImmediateValue(p, args...) \
78 NV50_IR_PROG_ALLOC_OBJ_DEF(ImmediateValue, p, args)
79
80
81 #define delete_Instruction(p, insn) (p)->releaseInstruction(insn)
82 #define delete_Value(p, val) (p)->releaseValue(val)
83
84
85 namespace nv50_ir {
86
87 class Iterator
88 {
89 public:
~Iterator()90 virtual ~Iterator() { };
91 virtual void next() = 0;
92 virtual void *get() const = 0;
93 virtual bool end() const = 0; // if true, get will return 0
reset()94 virtual void reset() { assert(0); } // only for graph iterators
95 };
96
97 typedef std::unique_ptr<Iterator> IteratorRef;
98
99 class ManipIterator : public Iterator
100 {
101 public:
102 virtual bool insert(void *) = 0; // insert after current position
103 virtual void erase() = 0;
104 };
105
106 // WARNING: do not use a->prev/next for __item or __list
107
108 #define DLLIST_DEL(__item) \
109 do { \
110 (__item)->prev->next = (__item)->next; \
111 (__item)->next->prev = (__item)->prev; \
112 (__item)->next = (__item); \
113 (__item)->prev = (__item); \
114 } while(0)
115
116 #define DLLIST_ADDTAIL(__list, __item) \
117 do { \
118 (__item)->next = (__list); \
119 (__item)->prev = (__list)->prev; \
120 (__list)->prev->next = (__item); \
121 (__list)->prev = (__item); \
122 } while(0)
123
124 #define DLLIST_ADDHEAD(__list, __item) \
125 do { \
126 (__item)->prev = (__list); \
127 (__item)->next = (__list)->next; \
128 (__list)->next->prev = (__item); \
129 (__list)->next = (__item); \
130 } while(0)
131
132 #define DLLIST_MERGE(__listA, __listB, ty) \
133 do { \
134 ty prevB = (__listB)->prev; \
135 (__listA)->prev->next = (__listB); \
136 (__listB)->prev->next = (__listA); \
137 (__listB)->prev = (__listA)->prev; \
138 (__listA)->prev = prevB; \
139 } while(0)
140
141 #define DLLIST_EMPTY(__list) ((__list)->next == (__list))
142
143 #define DLLIST_FOR_EACH(list, it) \
144 for (DLList::Iterator it = (list)->iterator(); !(it).end(); (it).next())
145
146 class DLList
147 {
148 public:
149 class Item
150 {
151 public:
Item(void * priv)152 Item(void *priv) : next(this), prev(this), data(priv) { }
153
154 public:
155 Item *next;
156 Item *prev;
157 void *data;
158 };
159
DLList()160 DLList() : head(0) { }
~DLList()161 ~DLList() { clear(); }
162
insertHead(void * data)163 inline void insertHead(void *data)
164 {
165 Item *item = new Item(data);
166
167 assert(data);
168
169 item->prev = &head;
170 item->next = head.next;
171 head.next->prev = item;
172 head.next = item;
173 }
174
insertTail(void * data)175 inline void insertTail(void *data)
176 {
177 Item *item = new Item(data);
178
179 assert(data);
180
181 DLLIST_ADDTAIL(&head, item);
182 }
183
insert(void * data)184 inline void insert(void *data) { insertTail(data); }
185
186 void clear();
187
188 class Iterator : public ManipIterator
189 {
190 public:
Iterator(Item * head,bool r)191 Iterator(Item *head, bool r) : rev(r), pos(r ? head->prev : head->next),
192 term(head) { }
193
next()194 virtual void next() { if (!end()) pos = rev ? pos->prev : pos->next; }
get()195 virtual void *get() const { return pos->data; }
end()196 virtual bool end() const { return pos == term; }
197
198 // caution: if you're at end-2 and erase it, then do next, you're at end
199 virtual void erase();
200 virtual bool insert(void *data);
201
202 // move item to another list, no consistency with its iterators though
203 void moveToList(DLList&);
204
205 private:
206 const bool rev;
207 Item *pos;
208 Item *term;
209
210 friend class DLList;
211 };
212
erase(Iterator & pos)213 inline void erase(Iterator& pos)
214 {
215 pos.erase();
216 }
217
iterator()218 Iterator iterator()
219 {
220 return Iterator(&head, false);
221 }
222
revIterator()223 Iterator revIterator()
224 {
225 return Iterator(&head, true);
226 }
227
228 private:
229 Item head;
230 };
231
232 class Stack
233 {
234 public:
235 class Item {
236 public:
237 union {
238 void *p;
239 int i;
240 unsigned int u;
241 float f;
242 double d;
243 } u;
244
Item()245 Item() { memset(&u, 0, sizeof(u)); }
246 };
247
Stack()248 Stack() : size(0), limit(0), array(0) { }
~Stack()249 ~Stack() { if (array) FREE(array); }
250
push(int i)251 inline void push(int i) { Item data; data.u.i = i; push(data); }
push(unsigned int u)252 inline void push(unsigned int u) { Item data; data.u.u = u; push(data); }
push(void * p)253 inline void push(void *p) { Item data; data.u.p = p; push(data); }
push(float f)254 inline void push(float f) { Item data; data.u.f = f; push(data); }
255
push(Item data)256 inline void push(Item data)
257 {
258 if (size == limit)
259 resize();
260 array[size++] = data;
261 }
262
pop()263 inline Item pop()
264 {
265 if (!size) {
266 Item data;
267 assert(0);
268 return data;
269 }
270 return array[--size];
271 }
272
getSize()273 inline unsigned int getSize() { return size; }
274
peek()275 inline Item& peek() { assert(size); return array[size - 1]; }
276
277 void clear(bool releaseStorage = false)
278 {
279 if (releaseStorage && array)
280 FREE(array);
281 size = limit = 0;
282 }
283
284 void moveTo(Stack&); // move all items to target (not like push(pop()))
285
286 private:
resize()287 void resize()
288 {
289 unsigned int sizeOld, sizeNew;
290
291 sizeOld = limit * sizeof(Item);
292 limit = MAX2(4, limit + limit);
293 sizeNew = limit * sizeof(Item);
294
295 array = (Item *)REALLOC(array, sizeOld, sizeNew);
296 }
297
298 unsigned int size;
299 unsigned int limit;
300 Item *array;
301 };
302
303 class DynArray
304 {
305 public:
306 class Item
307 {
308 public:
309 union {
310 uint32_t u32;
311 void *p;
312 };
313 };
314
DynArray()315 DynArray() : data(NULL), size(0) { }
316
~DynArray()317 ~DynArray() { if (data) FREE(data); }
318
319 inline Item& operator[](unsigned int i)
320 {
321 if (i >= size)
322 resize(i);
323 return data[i];
324 }
325
326 inline const Item operator[](unsigned int i) const
327 {
328 return data[i];
329 }
330
resize(unsigned int index)331 void resize(unsigned int index)
332 {
333 const unsigned int oldSize = size * sizeof(Item);
334
335 if (!size)
336 size = 8;
337 while (size <= index)
338 size <<= 1;
339
340 data = (Item *)REALLOC(data, oldSize, size * sizeof(Item));
341 }
342
clear()343 void clear()
344 {
345 FREE(data);
346 data = NULL;
347 size = 0;
348 }
349
350 private:
351 Item *data;
352 unsigned int size;
353 };
354
355 class ArrayList
356 {
357 public:
ArrayList()358 ArrayList() : size(0) { }
359
insert(void * item,int & id)360 void insert(void *item, int& id)
361 {
362 id = ids.getSize() ? ids.pop().u.i : size++;
363 data[id].p = item;
364 }
365
remove(int & id)366 void remove(int& id)
367 {
368 const unsigned int uid = id;
369 assert(uid < size && data[id].p);
370 ids.push(uid);
371 data[uid].p = NULL;
372 id = -1;
373 }
374
getSize()375 inline int getSize() const { return size; }
376
get(unsigned int id)377 inline void *get(unsigned int id) { assert(id < size); return data[id].p; }
378
379 class Iterator : public nv50_ir::Iterator
380 {
381 public:
Iterator(const ArrayList * array)382 Iterator(const ArrayList *array) : pos(0), data(array->data)
383 {
384 size = array->getSize();
385 if (size)
386 nextValid();
387 }
388
nextValid()389 void nextValid() { while ((pos < size) && !data[pos].p) ++pos; }
390
next()391 void next() { if (pos < size) { ++pos; nextValid(); } }
get()392 void *get() const { assert(pos < size); return data[pos].p; }
end()393 bool end() const { return pos >= size; }
394
395 private:
396 unsigned int pos;
397 unsigned int size;
398 const DynArray& data;
399
400 friend class ArrayList;
401 };
402
iterator()403 Iterator iterator() const { return Iterator(this); }
404
clear()405 void clear()
406 {
407 data.clear();
408 ids.clear(true);
409 size = 0;
410 }
411
412 private:
413 DynArray data;
414 Stack ids;
415 unsigned int size;
416 };
417
418 class Interval
419 {
420 public:
Interval()421 Interval() : head(0), tail(0) { }
422 Interval(const Interval&);
423 ~Interval();
424
425 bool extend(int, int);
426 void insert(const Interval&);
427 void unify(Interval&); // clears source interval
428 void clear();
429
begin()430 inline int begin() const { return head ? head->bgn : -1; }
end()431 inline int end() const { checkTail(); return tail ? tail->end : -1; }
isEmpty()432 inline bool isEmpty() const { return !head; }
433 bool overlaps(const Interval&) const;
434 bool contains(int pos) const;
435
extent()436 inline int extent() const { return end() - begin(); }
437 int length() const;
438
439 void print() const;
440
441 inline void checkTail() const;
442
443 private:
444 class Range
445 {
446 public:
Range(int a,int b)447 Range(int a, int b) : next(0), bgn(a), end(b) { }
448
449 Range *next;
450 int bgn;
451 int end;
452
coalesce(Range ** ptail)453 void coalesce(Range **ptail)
454 {
455 Range *rnn;
456
457 while (next && end >= next->bgn) {
458 assert(bgn <= next->bgn);
459 rnn = next->next;
460 end = MAX2(end, next->end);
461 delete next;
462 next = rnn;
463 }
464 if (!next)
465 *ptail = this;
466 }
467 };
468
469 Range *head;
470 Range *tail;
471 };
472
473 class BitSet
474 {
475 public:
BitSet()476 BitSet() : marker(false), data(0), size(0) { }
BitSet(unsigned int nBits,bool zero)477 BitSet(unsigned int nBits, bool zero) : marker(false), data(0), size(0)
478 {
479 allocate(nBits, zero);
480 }
~BitSet()481 ~BitSet()
482 {
483 if (data)
484 FREE(data);
485 }
486
487 // allocate will keep old data iff size is unchanged
488 bool allocate(unsigned int nBits, bool zero);
489 bool resize(unsigned int nBits); // keep old data, zero additional bits
490
getSize()491 inline unsigned int getSize() const { return size; }
492
493 void fill(uint32_t val);
494
495 void setOr(BitSet *, BitSet *); // second BitSet may be NULL
496
set(unsigned int i)497 inline void set(unsigned int i)
498 {
499 assert(i < size);
500 data[i / 32] |= 1 << (i % 32);
501 }
502 // NOTE: range may not cross 32 bit boundary (implies n <= 32)
setRange(unsigned int i,unsigned int n)503 inline void setRange(unsigned int i, unsigned int n)
504 {
505 assert((i + n) <= size && (((i % 32) + n) <= 32));
506 data[i / 32] |= ((1 << n) - 1) << (i % 32);
507 }
setMask(unsigned int i,uint32_t m)508 inline void setMask(unsigned int i, uint32_t m)
509 {
510 assert(i < size);
511 data[i / 32] |= m;
512 }
513
clr(unsigned int i)514 inline void clr(unsigned int i)
515 {
516 assert(i < size);
517 data[i / 32] &= ~(1 << (i % 32));
518 }
519 // NOTE: range may not cross 32 bit boundary (implies n <= 32)
clrRange(unsigned int i,unsigned int n)520 inline void clrRange(unsigned int i, unsigned int n)
521 {
522 assert((i + n) <= size && (((i % 32) + n) <= 32));
523 data[i / 32] &= ~(((1 << n) - 1) << (i % 32));
524 }
525
test(unsigned int i)526 inline bool test(unsigned int i) const
527 {
528 assert(i < size);
529 return data[i / 32] & (1 << (i % 32));
530 }
531 // NOTE: range may not cross 32 bit boundary (implies n <= 32)
testRange(unsigned int i,unsigned int n)532 inline bool testRange(unsigned int i, unsigned int n) const
533 {
534 assert((i + n) <= size && (((i % 32) + n) <= 32));
535 return data[i / 32] & (((1 << n) - 1) << (i % 32));
536 }
537
538 // Find a range of count (<= 32) clear bits aligned to roundup_pow2(count).
539 int findFreeRange(unsigned int count, unsigned int max) const;
findFreeRange(unsigned int count)540 inline int findFreeRange(unsigned int count) const {
541 return findFreeRange(count, size);
542 }
543
544 BitSet& operator|=(const BitSet&);
545
546 BitSet& operator=(const BitSet& set)
547 {
548 assert(data && set.data);
549 assert(size == set.size);
550 memcpy(data, set.data, (set.size + 7) / 8);
551 return *this;
552 }
553
554 void andNot(const BitSet&);
555
556 // bits = (bits | setMask) & ~clrMask
periodicMask32(uint32_t setMask,uint32_t clrMask)557 inline void periodicMask32(uint32_t setMask, uint32_t clrMask)
558 {
559 for (unsigned int i = 0; i < (size + 31) / 32; ++i)
560 data[i] = (data[i] | setMask) & ~clrMask;
561 }
562
563 unsigned int popCount() const;
564
565 void print() const;
566
567 public:
568 bool marker; // for user
569
570 private:
571 uint32_t *data;
572 unsigned int size;
573 };
574
checkTail()575 void Interval::checkTail() const
576 {
577 #if NV50_DEBUG & NV50_DEBUG_PROG_RA
578 Range *r = head;
579 while (r->next)
580 r = r->next;
581 assert(tail == r);
582 #endif
583 }
584
585 class MemoryPool
586 {
587 private:
enlargeAllocationsArray(const unsigned int id,unsigned int nr)588 inline bool enlargeAllocationsArray(const unsigned int id, unsigned int nr)
589 {
590 const unsigned int size = sizeof(uint8_t *) * id;
591 const unsigned int incr = sizeof(uint8_t *) * nr;
592
593 uint8_t **alloc = (uint8_t **)REALLOC(allocArray, size, size + incr);
594 if (!alloc)
595 return false;
596 allocArray = alloc;
597 return true;
598 }
599
enlargeCapacity()600 inline bool enlargeCapacity()
601 {
602 const unsigned int id = count >> objStepLog2;
603
604 uint8_t *const mem = (uint8_t *)MALLOC(objSize << objStepLog2);
605 if (!mem)
606 return false;
607
608 if (!(id % 32)) {
609 if (!enlargeAllocationsArray(id, 32)) {
610 FREE(mem);
611 return false;
612 }
613 }
614 allocArray[id] = mem;
615 return true;
616 }
617
618 public:
MemoryPool(unsigned int size,unsigned int incr)619 MemoryPool(unsigned int size, unsigned int incr) : objSize(size),
620 objStepLog2(incr)
621 {
622 allocArray = NULL;
623 released = NULL;
624 count = 0;
625 }
626
~MemoryPool()627 ~MemoryPool()
628 {
629 unsigned int allocCount = (count + (1 << objStepLog2) - 1) >> objStepLog2;
630 for (unsigned int i = 0; i < allocCount && allocArray[i]; ++i)
631 FREE(allocArray[i]);
632 if (allocArray)
633 FREE(allocArray);
634 }
635
allocate()636 void *allocate()
637 {
638 void *ret;
639 const unsigned int mask = (1 << objStepLog2) - 1;
640
641 if (released) {
642 ret = released;
643 released = *(void **)released;
644 return ret;
645 }
646
647 if (!(count & mask))
648 if (!enlargeCapacity())
649 return NULL;
650
651 ret = allocArray[count >> objStepLog2] + (count & mask) * objSize;
652 ++count;
653 return ret;
654 }
655
release(void * ptr)656 void release(void *ptr)
657 {
658 *(void **)ptr = released;
659 released = ptr;
660 }
661
662 private:
663 uint8_t **allocArray; // array (list) of MALLOC allocations
664
665 void *released; // list of released objects
666
667 unsigned int count; // highest allocated object
668
669 const unsigned int objSize;
670 const unsigned int objStepLog2;
671 };
672
673 /**
674 * Composite object cloning policy.
675 *
676 * Encapsulates how sub-objects are to be handled (if at all) when a
677 * composite object is being cloned.
678 */
679 template<typename C>
680 class ClonePolicy
681 {
682 protected:
683 C *c;
684
685 public:
ClonePolicy(C * c)686 ClonePolicy(C *c) : c(c) {}
687
context()688 C *context() { return c; }
689
get(T * obj)690 template<typename T> T *get(T *obj)
691 {
692 void *clone = lookup(obj);
693 if (!clone)
694 clone = obj->clone(*this);
695 return reinterpret_cast<T *>(clone);
696 }
697
set(const T * obj,T * clone)698 template<typename T> void set(const T *obj, T *clone)
699 {
700 insert(obj, clone);
701 }
702
703 protected:
704 virtual void *lookup(void *obj) = 0;
705 virtual void insert(const void *obj, void *clone) = 0;
706 };
707
708 /**
709 * Shallow non-recursive cloning policy.
710 *
711 * Objects cloned with the "shallow" policy don't clone their
712 * children recursively, instead, the new copy shares its children
713 * with the original object.
714 */
715 template<typename C>
716 class ShallowClonePolicy : public ClonePolicy<C>
717 {
718 public:
ShallowClonePolicy(C * c)719 ShallowClonePolicy(C *c) : ClonePolicy<C>(c) {}
720
721 protected:
lookup(void * obj)722 virtual void *lookup(void *obj)
723 {
724 return obj;
725 }
726
insert(const void * obj,void * clone)727 virtual void insert(const void *obj, void *clone)
728 {
729 }
730 };
731
732 template<typename C, typename T>
cloneShallow(C * c,T * obj)733 inline T *cloneShallow(C *c, T *obj)
734 {
735 ShallowClonePolicy<C> pol(c);
736 return obj->clone(pol);
737 }
738
739 /**
740 * Recursive cloning policy.
741 *
742 * Objects cloned with the "deep" policy clone their children
743 * recursively, keeping track of what has already been cloned to
744 * avoid making several new copies of the same object.
745 */
746 template<typename C>
747 class DeepClonePolicy : public ClonePolicy<C>
748 {
749 public:
DeepClonePolicy(C * c)750 DeepClonePolicy(C *c) : ClonePolicy<C>(c) {}
751
752 private:
753 std::map<const void *, void *> map;
754
755 protected:
lookup(void * obj)756 virtual void *lookup(void *obj)
757 {
758 return map[obj];
759 }
760
insert(const void * obj,void * clone)761 virtual void insert(const void *obj, void *clone)
762 {
763 map[obj] = clone;
764 }
765 };
766
767 template<typename S, typename T>
768 struct bimap
769 {
770 std::map<S, T> forth;
771 std::map<T, S> back;
772
773 public:
bimapbimap774 bimap() : l(back), r(forth) { }
bimapbimap775 bimap(const bimap<S, T> &m)
776 : forth(m.forth), back(m.back), l(back), r(forth) { }
777
insertbimap778 void insert(const S &s, const T &t)
779 {
780 forth.insert(std::make_pair(s, t));
781 back.insert(std::make_pair(t, s));
782 }
783
784 typedef typename std::map<T, S>::const_iterator l_iterator;
785 const std::map<T, S> &l;
786 typedef typename std::map<S, T>::const_iterator r_iterator;
787 const std::map<S, T> &r;
788 };
789
790 } // namespace nv50_ir
791
792 #endif // __NV50_IR_UTIL_H__
793