• 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 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