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