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