• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 size (<= 32) clear bits aligned to roundup_pow2(size).
543    int findFreeRange(unsigned int size) const;
544 
545    BitSet& operator|=(const BitSet&);
546 
547    BitSet& operator=(const BitSet& set)
548    {
549       assert(data && set.data);
550       assert(size == set.size);
551       memcpy(data, set.data, (set.size + 7) / 8);
552       return *this;
553    }
554 
555    void andNot(const BitSet&);
556 
557    // bits = (bits | setMask) & ~clrMask
periodicMask32(uint32_t setMask,uint32_t clrMask)558    inline void periodicMask32(uint32_t setMask, uint32_t clrMask)
559    {
560       for (unsigned int i = 0; i < (size + 31) / 32; ++i)
561          data[i] = (data[i] | setMask) & ~clrMask;
562    }
563 
564    unsigned int popCount() const;
565 
566    void print() const;
567 
568 public:
569    bool marker; // for user
570 
571 private:
572    uint32_t *data;
573    unsigned int size;
574 };
575 
checkTail()576 void Interval::checkTail() const
577 {
578 #if NV50_DEBUG & NV50_DEBUG_PROG_RA
579    Range *r = head;
580    while (r->next)
581       r = r->next;
582    assert(tail == r);
583 #endif
584 }
585 
586 class MemoryPool
587 {
588 private:
enlargeAllocationsArray(const unsigned int id,unsigned int nr)589    inline bool enlargeAllocationsArray(const unsigned int id, unsigned int nr)
590    {
591       const unsigned int size = sizeof(uint8_t *) * id;
592       const unsigned int incr = sizeof(uint8_t *) * nr;
593 
594       uint8_t **alloc = (uint8_t **)REALLOC(allocArray, size, size + incr);
595       if (!alloc)
596          return false;
597       allocArray = alloc;
598       return true;
599    }
600 
enlargeCapacity()601    inline bool enlargeCapacity()
602    {
603       const unsigned int id = count >> objStepLog2;
604 
605       uint8_t *const mem = (uint8_t *)MALLOC(objSize << objStepLog2);
606       if (!mem)
607          return false;
608 
609       if (!(id % 32)) {
610          if (!enlargeAllocationsArray(id, 32)) {
611             FREE(mem);
612             return false;
613          }
614       }
615       allocArray[id] = mem;
616       return true;
617    }
618 
619 public:
MemoryPool(unsigned int size,unsigned int incr)620    MemoryPool(unsigned int size, unsigned int incr) : objSize(size),
621                                                       objStepLog2(incr)
622    {
623       allocArray = NULL;
624       released = NULL;
625       count = 0;
626    }
627 
~MemoryPool()628    ~MemoryPool()
629    {
630       unsigned int allocCount = (count + (1 << objStepLog2) - 1) >> objStepLog2;
631       for (unsigned int i = 0; i < allocCount && allocArray[i]; ++i)
632          FREE(allocArray[i]);
633       if (allocArray)
634          FREE(allocArray);
635    }
636 
allocate()637    void *allocate()
638    {
639       void *ret;
640       const unsigned int mask = (1 << objStepLog2) - 1;
641 
642       if (released) {
643          ret = released;
644          released = *(void **)released;
645          return ret;
646       }
647 
648       if (!(count & mask))
649          if (!enlargeCapacity())
650             return NULL;
651 
652       ret = allocArray[count >> objStepLog2] + (count & mask) * objSize;
653       ++count;
654       return ret;
655    }
656 
release(void * ptr)657    void release(void *ptr)
658    {
659       *(void **)ptr = released;
660       released = ptr;
661    }
662 
663 private:
664    uint8_t **allocArray; // array (list) of MALLOC allocations
665 
666    void *released; // list of released objects
667 
668    unsigned int count; // highest allocated object
669 
670    const unsigned int objSize;
671    const unsigned int objStepLog2;
672 };
673 
674 /**
675  *  Composite object cloning policy.
676  *
677  *  Encapsulates how sub-objects are to be handled (if at all) when a
678  *  composite object is being cloned.
679  */
680 template<typename C>
681 class ClonePolicy
682 {
683 protected:
684    C *c;
685 
686 public:
ClonePolicy(C * c)687    ClonePolicy(C *c) : c(c) {}
688 
context()689    C *context() { return c; }
690 
get(T * obj)691    template<typename T> T *get(T *obj)
692    {
693       void *clone = lookup(obj);
694       if (!clone)
695          clone = obj->clone(*this);
696       return reinterpret_cast<T *>(clone);
697    }
698 
set(const T * obj,T * clone)699    template<typename T> void set(const T *obj, T *clone)
700    {
701       insert(obj, clone);
702    }
703 
704 protected:
705    virtual void *lookup(void *obj) = 0;
706    virtual void insert(const void *obj, void *clone) = 0;
707 };
708 
709 /**
710  *  Shallow non-recursive cloning policy.
711  *
712  *  Objects cloned with the "shallow" policy don't clone their
713  *  children recursively, instead, the new copy shares its children
714  *  with the original object.
715  */
716 template<typename C>
717 class ShallowClonePolicy : public ClonePolicy<C>
718 {
719 public:
ShallowClonePolicy(C * c)720    ShallowClonePolicy(C *c) : ClonePolicy<C>(c) {}
721 
722 protected:
lookup(void * obj)723    virtual void *lookup(void *obj)
724    {
725       return obj;
726    }
727 
insert(const void * obj,void * clone)728    virtual void insert(const void *obj, void *clone)
729    {
730    }
731 };
732 
733 template<typename C, typename T>
cloneShallow(C * c,T * obj)734 inline T *cloneShallow(C *c, T *obj)
735 {
736    ShallowClonePolicy<C> pol(c);
737    return obj->clone(pol);
738 }
739 
740 /**
741  *  Recursive cloning policy.
742  *
743  *  Objects cloned with the "deep" policy clone their children
744  *  recursively, keeping track of what has already been cloned to
745  *  avoid making several new copies of the same object.
746  */
747 template<typename C>
748 class DeepClonePolicy : public ClonePolicy<C>
749 {
750 public:
DeepClonePolicy(C * c)751    DeepClonePolicy(C *c) : ClonePolicy<C>(c) {}
752 
753 private:
754    std::map<const void *, void *> map;
755 
756 protected:
lookup(void * obj)757    virtual void *lookup(void *obj)
758    {
759       return map[obj];
760    }
761 
insert(const void * obj,void * clone)762    virtual void insert(const void *obj, void *clone)
763    {
764       map[obj] = clone;
765    }
766 };
767 
768 template<typename S, typename T>
769 struct bimap
770 {
771    std::map<S, T> forth;
772    std::map<T, S> back;
773 
774 public:
bimapbimap775    bimap() : l(back), r(forth) { }
bimapbimap776    bimap(const bimap<S, T> &m)
777       : forth(m.forth), back(m.back), l(back), r(forth) { }
778 
insertbimap779    void insert(const S &s, const T &t)
780    {
781       forth.insert(std::make_pair(s, t));
782       back.insert(std::make_pair(t, s));
783    }
784 
785    typedef typename std::map<T, S>::const_iterator l_iterator;
786    const std::map<T, S> &l;
787    typedef typename std::map<S, T>::const_iterator r_iterator;
788    const std::map<S, T> &r;
789 };
790 
791 } // namespace nv50_ir
792 
793 #endif // __NV50_IR_UTIL_H__
794